C语言变长参数
说起C语言的变长参数,可能听起来比较陌生,因为很少会需要自己实现。不过想一下scanf和printf,参数个数的确是不固定的。
stdarg.h 中提供以一套机制来实现变长参数。以及,要说明的是,变长参数不是什么黑魔法,原理依赖于stack frame的结构,具体可以参考x86-calling-conventions 简单来说,由于函数参数入栈的顺序是固定的,**因此一旦我们知道某函数帧的栈上的一个固定参数的位置,我们完全有可能推导出其他变长参数的位置 **
在实现上,需要了解的是:
* va_list,一个类型,可以看做是变长参数列表;
* [va_start](http://en.cppreference.com/w/cpp/utility/variadic/va_start),用来初始化变长参数列表的宏,声明为void va_start( va_list ap, parm_n ); ap为va_list变量,parm_n为变长参数前一个变量(C语言要求至少有一个named variable作为函数的parameter)
* [va_arg](http://en.cppreference.com/w/cpp/utility/variadic/va_arg),用来得到下一个参数的宏,声明为T va_arg( va_list ap, T ); **返回的类型取决于传入的类型T。特别注意:"If `va_arg` is called when there are no more arguments in `ap`, the behavior is undefined."**
* [va_end](http://en.cppreference.com/w/cpp/utility/variadic/va_end) ,用来将va_list释放的宏。
下面看一个例子就明白怎么用了orz
1 #include <stdio.h>
2 #include <stdarg.h>
3
4 /* print all args one at a time until a negative argument is seen;
5 all args are assumed to be of int type */
6 void printargs(int arg1, ...)
7 {
8 va_list ap;
9 int i;
10
11 va_start(ap, arg1);
12 for (i = arg1; i >= 0; i = va_arg(ap, int))
13 printf("%d ", i);
14 va_end(ap);
15 putchar('\n');
16 }
17
18 int main(void)
19 {
20 printargs(5, 2, 14, 84, 97, 15, -1, 48, -1);
21 printargs(84, 51, -1);
22 printargs(-1);
23 printargs(1, -1);
24 return 0;
25 }
26
27
28 output:
29 5 2 14 84 97 15
30 84 51
31
32 1
如果想研究c语言中变长参数的具体实现,可以参考 也谈C语言变长参数
参考资料: