第七章 函数(二)

可变函数
可变参数列表通过宏来实现,定义于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中重新获取这两项。
Posted on 2013-07-01 23:14 烽火依然 阅读(130) 评论(0)   编辑  收藏 引用 所属分类: c和指针

你可能感兴趣的:(第七章 函数(二))