c的可变参数(va_arg,va_list,va_start,va_end)
首先是头文件. <stdarg.h>
其次, 我们的目的是实现支持变长参数的函数, 但并不是说,这个函数参数可以全都是变的. 不行. 函数的参数列表中, 一定至少要有一个有name的参数. 比如printf, 它的定义是printf(const char * restrict format, ...);
也是有restrict format这个有name的参数的. 变参正如printf显示的那样, 是...
好了, 怎么用呢. 我们拿一个网上博客的例子. 出处是深入C语言可变参数(va_arg,va_list,va_start,va_end)
#include <stdio.h>
#include <stdarg.h>
void print_args(int count, ...);
int main(int argc, char* argv[]) {
print_args(5,1,2,3,4,5);
return 0;
}
void print_args(int count, ...) {
int i, value;
va_list arg_ptr;
va_start(arg_ptr, count);
for(i=0; i<count; i++) {
value = va_arg(arg_ptr,int);
printf("position %d = %d\n", i+1, value);
}
va_end(arg_ptr);
}
首先看函数的定义, 有一个有name的参数count, 除此之外就是变参...
要获得变参, 首先需要定义一个va_list类型的变量, 这里是va_list arg_ptr;
. 这个类型的变量, 之后会遍历获取到所有的参数, 这个变量我们会一直用, 一直到参数解析完毕.
但这个变量使用前必须初始化, 我们看到是va_start(arg_ptr, count);
, 这个函数实际上是一个宏. 它需要两个参数, 第一个是va_list类型的遍历变量, 第二个参数是这个函数最后一个有name的参数, 这里就是count. 但是va_start的作用是什么呢?
The macro va_start initializes ap to point to the first unnamed argument.
让它指向第一个unnamed的参数.
好了, 那么怎么获得变参呢? 这就是value = va_arg(arg_ptr,int);
, 第一个参数自然是va_list
类型, 第二个参数是指定类型, 这样才知道它占的内存大小, 才知道它占了多少, 下一步该到内存什么位置. 返回就会返回int类型的. 这个va_arg
应该也是宏.
最后必须在函数返回前调用va_end, K&R是这么说的:
Finally, va_end does whatever cleanup is necessary.
好了再总结使用要点:
- 头文件是<stdarg.h>
- 先定义va_list变量, 然后va_start它, 第二个参数是最后一个named参数
- va_arg(va_list变量, 类型)解析参数, 返回就是我们调用的参数.
- 最后用va_end释放va_list变量.