变参宏:...__VA_ARGS__

 #define PR(...) printf(__VA_ARGS__);

注意:省略号只能代替最后的宏参数

 #define WRONG(X, ..., Y) #X #__VA_ARGS__ #Y // 不能这样做

可变参数:stdarg.h

stdarg.h 为函数提供了可变参数的功能。但是用法比较复杂。必须按照如下步骤进行:

  1. 提供一个使用省略号的函数原型;

  2. 在函数定义中创建一个 va_list 类型的变量;

  3. 用宏把该变量初始化为一个参数列表;

  4. 用宏访问参数列表;

  5. 用宏完成清理工作。

这种函数的原型应该有一个形参列表,其中至少有一个形参和一个省略号,省略号必须放在最后。

声明在 stdarg.h 中的 va_list 类型代表一种用于储存形参列表中省略号部分的数据对象。

 #include <stdio.h>
 #include <stdarg.h>
 ​
 double sum(int lim, ...)
 {
     va_list ap; // 声明一个对象存储参数
     double tot = 0;
     
     va_start(ap, lim); // 把ap初始化为参数列表
     
     for(int i = 0; i < lim; ++i)
         tot += va_arg(ap, double); // 访问参数列表中的每一项
     
     va_end(ap); // 清理工作
     
     return tot;
 }
 ​
 int main()
 {
     printf("%lf\n", sum(3, 1.1, 2.2, 3.3));
     
     return 0;
 }

注意:传入的实参类型必须与宏参数的类型相匹配。如果第一个参数是 10.0va_arg(ap, double) 可以正常工作。但是如果参数是 10 ,此代码可能会出错。这里不会像赋值那样把 int 类型自动转换成 double 类型。

注意:va_start() 宏的第 2 个参数必须是 ... 前第 1 个形参,用以标记可变参数的位置。

最后,要使用 va_end() 宏完成清理工作。例如,释放动态分配用于存储参数的内容。该宏接受一个 va_list 类型的变量。

调用 va_end(ap) 之后,只有用 va_start 重新初始化 ap 后,才能使用变量 ap

因为 va_arg() 不提供退回之前参数的方法,所以有必要保存 va_list 类型变量的副本。C99 新增了一个宏用于处理这种情况:va_copy() 。该宏接受两个 va_list 类型的变量作为参数,它把第 2 个参数拷贝给第 1 个参数:

 va_list ap;
 va_iist apcopy;
 ​
 double tic;
 int toc;
 ​
 // ...
 ​
 va_start(ap, lim); // 把ap初始化为一个参数列表
 va_copy(apcopy, ap); // 把apcopy作为ap的副本
 tic = va_arg(ap, double); // 检索第1个参数
 toc = va_arg(ap, int); // 检索第2个参数

此时,即使删除了 ap ,也可以从 apcopy 中检索两个参数。


文章作者: Amelie
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 个人技术心得
编程 C语言 编程 C语言
喜欢就支持一下吧