可变长度参数在C语言里面不算什么新鲜的东西,但是它的应用范围很广,属于基础知识范围,因此将这个话题做为系列文章中的第一篇比较合适。
什么是可变长度参数呢?拿printf()来举例:
printf("This is an integer: %d, That is a float: %s", 1, 2.0);
在上面的例子里,printf()接收三个参数,第一个是要打印的字串,里面有两个参数:
* %d
* %s
后面是这两个参数对应的实际值:
* 1
* 2.0
在上面的例子里,printf()接收了三个参数。再看下面这个例子:
printf("Hello, world!");
printf()这次只接收了一个参数。换言之,printf()接收的参数个数是*可变的*。这是如何实现的呢?在C语言里面,我们可以在函数定义时使用 "..." 来定义可变长度参数,比如:
a_function(int i, ...);
先将固定参数写在最前面,后面再用"..."来声明这个函数接收可变长数参数。
然后,我们在函数内部使用stdarg.h里面定义的一个s
truct和几个宏来实现对可变长度参数的读取:
* va_list
* va_start()
* va_arg()
* va_end()
这个几东西的使用方法非常简单,在stdarg.h的manpage里面说明的很详细。查看stdarg.h的manpage可用下面的
命令:
man 3 stdarg
里面有这样一段说明:
引用
The va_start() macro must be call
ed first, and it initializes ap,
which can be pas
sed to va_arg() for each argument to be processed. Calling va_end() signa
ls that there are no further arguments, and causes ap to be invali
dated. Note that each call to va_start() must be matched by a call to va_end(), from within the same function.
简单翻译一下,就是首先调用va_start(),然后初始化ap,之后使用va_arg()来处理可变长度参数。最后,使用va_end()来清理ap。
我制作了一个实际的例子,放在了
github上面:
https://github.com/liweinan/learnc/blob/master/stdarg.c
关于这个代码,有些要说明的地方:
* 这里面有两个可变长度参度的函数:一个是求平均数的average(),另一个是模拟printf的min_printf()
* average()这个函数想说明的是:第一个固定参数在实际应用时是必不可少的,需要它的配合来使用后面的参数。
* min_printf()这个函数想说明的是: 如何使用第一个固定参数里面的值配合读取后面可变长度参数的数据类型。
代码里面的说明已经很详细,可以仔细看下。下面是这个例子的使用方法:
首先从git迁出代码:
git clone git://github.com/liweinan/learnc.git
然后编译例子:
make stdarg.o
最后运行例子,下面是命令和输出结果:
% make play_stdarg
./stdarg.o
average: 2.300000
The ultimate answer of life is: 42