可变参数stdarg.h
变参宏:该宏可以接受可变数量的参数
步骤
-
提供一个可以使用省略号的函数原型
省略号在最末尾;有形参
void f1(int n, ...); // 有效 int f2(const char * s, int k, ...); // 有效 char f3(char c1, ..., char c2); // 无效,省略号不在最后 double f3(...); // 无效,没有形参
最右边的形参起着特殊作用,标准中用parmN这个术语来描述该参数。
传递给该形参的实际参数是省略号部分代表的参数数量
f1(2, 200, 400); // 2个额外的参数 f1(4, 13, 117, 18, 23); // 4个额外的参数
-
在函数定义中创造一个va_list类型的变量
va_list类型代表着一种用于存储形参对应的形参列表中省略号部分的数据对象
double sum(int lim,...){ //lim是parmN形参,它表明变参列表中参数的数量 va_list ap; //声明一个存储参数的对象
-
用宏把该变量初始化为一个参数列表
使用定义中的va_start()宏,把参数列表拷贝到va_list类型的变量中,该宏有两个参数,va_list类型的变量和parmN形参
va_start(ap,lim); //把ap初始化为参数列表
-
用宏访问参数列表;
涉及使用一个宏va_arg(),该宏接受两个参数,一个va_list类型的变量和一个数据类型名
第一次调用va_arg()返回参数列表中的第1项,第二次调用时返回第2项。以此类推,表示类型的参数指定了返回值的类型
传入的参数类型必须与宏参数类型相匹配,这里不会像赋值一样直接转换
va_start(ap,lim); //把ap初始化为参数列表 double tic; int toc; ... tic = va_arg(ap, double); // 检索第1个参数,如果为10 这行代码可能会出错 toc = va_arg(ap, int); //检索第2个参数
-
宏完成清理工作
用va_end()完成清理工作,例如释放动态分配内存用于存储参数的内存,该宏接受一个va_list类型的变量
va_end(ap);
调用此函数后,只有使用va_start()重新初始化ap后,才能使用变量ap
-
va_copy()保存副本
因为va_arg()不提供退回之前参数的方法,所以有必要保存va_list类型变量的副本
va_copy()该宏接受两个va_list类型变量作为副本,把第2个参数拷贝给第1个参数
va_list ap;
va_list apcopy;
double tic;
int toc;
...
va_start(ap,lim);
va_copy(apcopy,ap);
tic=va_arg(ap,double); //检索第一个参数
toc=va_arg(ap,int); //检索第二个参数
应用
#include <stdio.h>
#include <stdarg.h>
double sum(int, ...);
int main(void){
double s, t;
s = sum(3, 1.1, 2.5, 13.3);
t = sum(6, 1.1, 2.1, 13.1, 4.1, 5.1, 6.1);
printf("return value for "
"sum(3, 1.1, 2.5, 13.3): %g\n", s);
printf("return value for "
"sum(6, 1.1, 2.1, 13.1, 4.1, 5.1, 6.1): %g\n", t);
}
double sum(int lim, ...){
va_list ap; // 声明一个对象存储参数
double tot = 0;
int i;
va_start(ap, lim); // 把ap初始化为参数列表
for (i = 0; i < lim; i++)
tot += va_arg(ap, double); // 访问参数列表中的每一项
va_end(ap); // 清理工作
return tot;
}