C语言中支持可变长参数的函数,比如
1: #include "stdarg.h"
2:
3: void f(char* format, ...);
4:
5: void f(char* format, ...)
6: {
7: va_list args;
8: int numArgs;
9: int arg[10];
10:
11: va_start(args, format);
12: numArgs = va_arg(args, int);
13: for (i=0; i!=numArgs; i++) {
14: arg[i] = va_arg(args, int);
15: printf("The No.%d argument is %d\n", arg[i]);
16: }
17: va_end(args);
18: }
#1
stdarg.h
支持可变长参数函数的头文件
#7
va_list args;
声明一个用以容纳可变长参数的数据结构
#11
va_start(format, args);
format是可变长参数前的最后一个固定参数,用以定位,这是C语言中可变长参数的一种限制
#12
#14
va_arg(args, type);
从可变长参数中弹出一个type类型参数
#17
va_end(args);
可变长参数使用结束
不过在C里并没有指定可变长参数实际个数的函数,在这个例子里,可变长参数的第一个int类型被设计成后续参数个数,程序中将这个值放入numArgs,再逐一取出后续的值。也可以有另外的约定策略,比如一个printf型的函数
1: void writelocalbuf(char *fmt, ...)
2: {
3: va_list args;
4: char *p;
5: int val;
6: char valStr[20];
7: char* str;
8:
9: va_start(args, fmt);
10:
11: for (p = fmt; *p; p++) {
12: if (*p != '%') {
13: writeChar2Buf(*p);
14: continue;
15: }
16:
17: /*Special Processing*/
18: switch (*++p) {
19: case 'd':
20: val = va_arg(args, int);
21: sprintf(valStr, "%d", val);
22: writelocalbuf(valStr);
23: break;
24: case 'x':
25: val = va_arg(args, int);
26: sprintf(valStr, "%x", val);
27: writelocalbuf(valStr);
28: break;
29: case 's':
30: str = va_arg(args, char*);
31: writelocalbuf(str);
32: break;
33: default:
34: writeChar2Buf('%');
35: writeChar2Buf(*p);
36: break;
37: }
38: }
39:
40: va_end(args);
41: }
这个函数里fmt字符串内所有的诸如”%d””%x””%s”都会被视作一个约定的标记,在后续的可变长参数内依次约定一个对应的数据,可能是int数值,也可能是char*字符串。这个函数本身也用到了迭代的方法,这里就不详细展开讨论了。
接下来一个问题是可变长参数如何进行多层的传递,下面是一个例子
1: void func_api(ele_type* ele, ...)
2: {
3: va_list args;
4: va_start(ele, args);
5: ele->func(args);
6: va_end(args);
7: }
8:
9: // implementation of ele->func
10: void func_ele(va_list args)
11: {
12: int numArgs = va_arg(args, int);
13: int i;
14: int args[i];
15: for (i=0; i!=numArgs; i++) {
16: args[i] = va_arg(args, int);
17: printf("arg is %d\n", args[i]);
18: }
19: }
这是一个很常见的二级传递,第一级是一个API Wapper,第一个参数为对象实体,后面的可变长参数是想传给这个实体的数据。
#5
调用实体ele的entry function,从#10可以看到,这个entry function已经不再用…的形式直接接受可变长参数,而是将上层解析出的va_list直接传递下来,然后用va_arg逐一抽取
Like this:
Like Loading...
Related