C傳遞可變參數(shù)
va_list
??va_list配合va_start/va_arg/va_end宏定義, 可以完成C語言中可變參數(shù)的傳遞獲取. 需要注意的是, 必須有一個(gè)固定參數(shù); 其次三個(gè)宏的使用必須嚴(yán)格一致。
示例
#include <stdarg.h>
#include <stdio.h>
void test1(int n, ...)
{
va_list ap;
va_start(ap, n);
const char *tmp = NULL;
for(int i = 0; i < n; i++)
{
tmp = va_arg(ap, const char*);
if(tmp)
{
printf("%s ", tmp);
}
}
}
int main()
{
test1(3, "a", "b", "c", "d");
return 0;
}
結(jié)果
a b c
注意事項(xiàng)
- 1 我們通常使用第一個(gè)值作為可變參數(shù)的個(gè)數(shù); 但是實(shí)際中我們?cè)俸瘮?shù)內(nèi)無法得到傳遞的參數(shù)個(gè)數(shù), 我們可以無限制的調(diào)用
va_arg, 假設(shè)我們將循環(huán)次數(shù)改為4次, 最后一次獲取的值是不確定的, 如下是亂碼.
a b c ?(
- 2 這個(gè)函數(shù)的使用是不嚴(yán)格且不安全的
自己實(shí)現(xiàn)可變參數(shù)傳遞
??首先我們需要明白函數(shù)入棧的規(guī)則, 函數(shù)參數(shù)入棧從右到左; 如果我們知道第一個(gè)參數(shù)的地址并且知道參數(shù)的類型, 我們就可以得到其余參數(shù)的地址了. 這就是va_list需要一個(gè)固定參數(shù)的原因, 如果沒有該固定參數(shù)我們是無法進(jìn)行任何操作的.
參數(shù)類型是否必須一致?
#include <stdio.h>
#include <stdlib.h>
void func(int a, ...)
{
}
void main()
{
int a = 10;
short b = 10;
printf("sizeof int: %d\n", sizeof(int));
printf("sizeof ptr: %d\n", sizeof(char*));
printf("sizeof short: %d\n", sizeof(short));
func(a, "hello", b, "world");
}
結(jié)果是:
sizeof int: 4
sizeof ptr: 4
sizeof short: 2
可以成功編譯通過并執(zhí)行, 可以得知編譯器內(nèi)部并沒有做特別詳細(xì)的判斷和區(qū)分; 那么就會(huì)引入一個(gè)新的問題, 由于不同類型的字節(jié)數(shù)不同, 會(huì)不會(huì)產(chǎn)生字節(jié)對(duì)齊的問題?
會(huì)不會(huì)產(chǎn)生字節(jié)對(duì)齊?
#include <stdio.h>
#include <stdlib.h>
void func(int a, ...)
{
const char *argv = (const char *)&a; //指向棧的指針
int Arg1 = a;
printf("Arg[1]: %d\n", Arg1);
const char *Arg2 = *(const char **)(argv + 4);
//將指向棧中第二個(gè)參數(shù)的指針轉(zhuǎn)換為為指向字符串指針的指針, 再進(jìn)行解引用就可以獲得棧中的字符串指針
printf("arg[2]: %s\n", Arg2);
short Arg3 = *(short*)(argv + 8);
printf("arg[3]: %d\n", Arg3);
const char *Arg4 = *(const char**)(argv + 12);
printf("arg[4]: %s\n", Arg4);
}
void main()
{
int a = 10;
short b = 100;
printf("sizeof int: %d\n", sizeof(int));
printf("sizeof ptr: %d\n", sizeof(char*));
printf("sizeof short: %d\n", sizeof(short));
func(a, "hello", b, "world");
}
結(jié)果:
sizeof int: 4
sizeof ptr: 4
sizeof short: 2
Arg[1]: 10
arg[2]: hello
arg[3]: 100
arg[4]: world
結(jié)論: 產(chǎn)生了字節(jié)對(duì)齊