c的可变参数(va_arg,va_list,va_start,va_end)

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
", 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变量.