可变函数
可变参数列表通过宏来实现,定义于stdarg.h头文件,是标准库的一部分。
这个头文件声明了一个类型va_list和三个宏--va_start、va_arg和va_end。
声明一个类型为va_list的变量,与几个宏配合使用,访问参数的值。
函数的使用方法必须按如下步骤进行:
1.在函数原型中使用省略号。
2.在函数定义中创建一个va_list类型的变量。
3.用宏将该变量初始化为一个参数列表。
4.用宏访问这个参数列表。
5.用宏完成清理工作。
注:这类函数的原型应该具有一个
参量列表,参量列表中至少有一个后跟省略号的参量,即:省略号前至少要有一个有名字的参数。
宏的使用1.va_start初始化va_list变量,宏va_start接受两个参数:va_list变量和省略号前最后一个有名字的参数。
2.通过va_arg访问参数,宏va_arg接受两个参数:va_list变量和
参数列表中下一个参数的类型。注:
实际参数类型必须与说明的类型相匹配,如果参数列表中第一个参数为double型,第二个参数为int型,那么va_arg必须做调整。
1 double tic;
2 int toc;
3
4 tic = va_arg( var_arg, double );
5 toc = va_arg( var_arg, int );
3.va_end:访问完最后一个可变参数后,需要调用va_end,参数:va_list变量。
实例:
average.c
1 /*
2 **计算指定数量的值的平均值。
3 */
4 #include< stdarg.h >
5
6 float
7 average( int n_values, )
8 {
9 va_list var_arg;
10 int count;
11 float sum = 0;
12
13 /*
14 **准备访问可变参数。
15 */
16 va_start( var_arg, n_values );
17
18 /*
19 **添加取自可变参数列表的值。
20 */
21 for( count = 0; count < n_values; count += 1 )
22 {
23 sum += va_arg( var_arg, int );
24 }
25
26 /*
27 **完成处理可变参数。
28 */
29 va_end( var_arg );
30
31 return sum/n_values;
32 }
33 vc下测试: 1 #include< stdio.h >
2 #include< stdarg.h >
3
4 void test( char a, char b, );
5
6 int main( void )
7 {
8 char a,b;
9 b='a';//如果b不初始化,输出垃圾值。
10
11 test( a, b, 1, 3, 'd', b, '*' );
12
13 return 0;
14 }
15
16 void test( char a, char b, )
17 {
18 va_list var_arg;
19
20 va_start( var_arg, a );
21
22 for( int i = 0; i < 8; i++ )
23 printf("%d\n",va_arg( var_arg, int ));
24
25 va_end( var_arg );
26 }
运行结果:
结果说明:
1.代码第20行va_start宏的第二个参数是a,并不是省略号的前一个参数,
说明:关于va_list第二个参数:不一定是省略号前最后一个有名字参数,在vc下测试时,倒数第二个参数也能正常运行。
2.最后两行输出值为0,可变参数为5个,小于for循环中的循环控制变量;
说明:当访问完最后一个可变参数后,调用va_arg( var_arg, type );的返回值恒为
0(vc6.0测试)。
3.当将第11代码test中的 '*'换成一个float类型的变量c = 1.0;在结果中值却是0;是什么原因?
结果如下图:
va_arg()不提供退回前参数的方法,所以保存va_list的副本会是有用的。
c99为此添加了宏va_copy(),接受两个va_list变量,将第二个参数复制到第一个参数中:
1 va_list ap;
2 va_list apcopy;
3 double tic;
4 double toc;
5
6 va_start( ap, lim ); //把ap初始化为参数列表
7 va_copy( apcopy, ap ); //apcopy是ap的一个副本
8 tic = va_arg( ap, double ); //取得第一个参数
9 toc = va_arg( ap, int ); //取得第二个参数 此时,虽然已从ap中删除了前面两项,但还可以从apcopy中重新获取这两项。