侧边栏壁纸
博主头像
Amelie

但行好事,莫问前程

  • 累计撰写 19 篇文章
  • 累计创建 34 个标签
  • 累计收到 0 条评论

C语言变参宏和可变参数函数

Amelie
2021-04-26 / 0 评论 / 0 点赞 / 185 阅读 / 1,185 字
温馨提示:
本文最后更新于 2022-03-11,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

变参宏:...__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 中检索两个参数。

0

评论区