可变参数宏定义

C99编译器标准允许你可以定义可变参数宏(variadic macros),这样你就可以使用拥有可以变化的参数表的宏。可变参数宏就像下面这个样子:

#define dbgprint(...) printf(__VA_ARGS__)

缺省号代表一个可以变化的参数表。使用保留名 __VA_ARGS__ 把参数传递给宏。当宏的调用展开时,实际的参数就传递给 printf()了。

可变参数宏不被ANSI/ISO C++ 所正式支持。因此,你应当检查你的编译器,看它是否支持这项技术。

用GCC和C99的可变参数宏, 更方便地打印调试信息

#ifdef DEBUG
#define dbgprint(format, ...) \
fprintf(stderr, format, __VA_ARGS__)
#else
#define dbgprint(format, ...)
#endif

在标准C里,你不能省略可变参数,但是你却可以给它传递一个空的参数。例如,下面的宏调用在ISO C里是非法的,因为字符串后面没有逗号:

dbgprint ("A message") 

GNU CPP在这种情况下可以让你完全的忽略可变参数。在上面的例子中,编译器仍然会有问题(complain),因为宏展开后,里面的字符串后面会有个多余的逗号。

为了解决这个问题,CPP使用一个特殊的'##'操作。书写格式为:

#define dbgprint(format, ...) fprintf (stderr, format, ## __VA_ARGS__)

这里,如果可变参数被忽略或为空,'##'操作将使预处理器(preprocessor)去除掉它前面的那个逗号。

如果你在宏调用时,确实提供了一些可变参数,GNU CPP也会工作正常,
它会把这些可变参数放到逗号的后面。象其它的pasted macro参数一样,这些参数不是宏的扩展。

/* C语言 宏定义之可变参数 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h> #define MDEBUG #ifdef MDEBUG
#define TEST_LOG(format,...) fprintf(stderr, format, ##__VA_ARGS__)
#else
#define TEST_LOG(format,...)
#endif int test()
{
int num = ;
TEST_LOG("my num is %d .\n", num);
return num;
} int main()
{
test();
printf("--------ok-------\n");
return ;
}

C语言 宏定义之可变参数的更多相关文章

  1. GNU中宏定义对可变参数的支持(引自百度)

    http://zhidao.baidu.com/question/125413478.html 问:#define PDEBUG(fmt,args...) fprintf(stderr,fmt, ## ...

  2. C函数和宏中的可变参数

    一:调用惯例 函数的调用方和被调用方对函数如何调用应该有统一的理解,否则函数就无法正确调用.比如foo(int n, int m),调用方如果认为压栈顺序是m,n,而foo认为压栈顺序是n, m,那么 ...

  3. c语言宏定义

    一. #define是C语言中提供的宏定义命令,其主要目的是为程序员在编程时提供一定的方便,并能在一定程度上提高程序的运行效率,但学生在学习时往往不能理解该命令的本质,总是在此处产生一些困惑,在编程时 ...

  4. 将C语言宏定义数值转换成字符串!

    将C语言宏定义转换成字符串! 摘自:https://blog.csdn.net/happen23/article/details/50602667 2016年01月28日 19:15:47 六个九十度 ...

  5. C语言宏定义#define用法

    #define是C语言中提供的宏定义命令,其主要目的是为程序员在编程时提供一定的方便,并能在一定程度上提高程序的运行效率,但学生在学习时往往不能 理解该命令的本质,总是在此处产生一些困惑,在编程时误用 ...

  6. C 语言宏定义

    C 语言宏定义1.例子如下: #define PRINT_STR(s) printf("%s",s.c_str()) string str = "abcd"; ...

  7. 宏定义(无参宏定义和带参宏定义),C语言宏定义详解

    1.宏定义说明 宏定义是比较常用的预处理指令,即使用"标识符"来表示"替换列表"中的内容.标识符称为宏名,在预处理过程中,预处理器会把源程序中所有宏名,替换成宏 ...

  8. 嵌入式C语言自我修养 12:有一种宏,叫可变参数宏

    12.1 什么是可变参数宏 在上面的教程中,我们学会了变参函数的定义和使用,基本套路就是使用 va_list.va_start.va_end 等宏,去解析那些可变参数列表我们找到这些参数的存储地址后, ...

  9. C语言可变参数宏及‘##’在可变参数中的作用

    测试代码及解释: #include <stdio.h> #define PRINT(x) printf x #define SECONDPRINT(fmt,arg...) printf(f ...

随机推荐

  1. temsorflow使用笔记(自用)

    tf.argmax(input, axis=None, name=None, dimension=None) 功能:查找最大值的索引 input:数据: axis:定义按照某一条轴进行查找,如: ax ...

  2. saltstack--状态判断unless与onlyif

    saltstack状态判断unless与onlyif 很多时候我们在编写 state 文件时候需要进行判断,判断该目录或文件是否存在,判断该配置是否已经已添加,然后根据判断结果再决定命令或动作是否执行 ...

  3. 熟练掌握GitHub及Git的使用方法

    一.Git 命令的理解和使用 Git是一个快速,可扩展的分布式版本控制系统,具有异常丰富的命令集,可提供高级操作和对内部的完全访问. 分布式:Git版本控制系统是一个分布式的系统,是用来保存工程源代码 ...

  4. Beta冲刺第6次

    二.Scrum部分 1. 各成员情况 翟仕佶 学号:201731103226 今日进展 新增图像拼接合并功能 存在问题 无 明日安排 视情况而定 截图 曾中杰 学号:201731062517 今日进展 ...

  5. BitMap 图片格式与Base64Image格式互转方法

    BitMap 图片格式与Base64Image格式互转方法 /// <summary> /// 图片转为base64编码的字符串 /// </summary> /// < ...

  6. cmds在线重定义增加列

    --输出信息采用缩排或换行格式化 EXEC DBMS_METADATA.set_transform_param(DBMS_METADATA.session_transform, 'PRETTY', T ...

  7. oracle数据库(六)

    存储过程和函数以及触发器 PL/SQL程序块都是匿名块,当需要再次调用这些程序块时,只能再次编写程序块的内容,然后又oracle重新编译执行,为了提高系统的应用性能,oracle提供了一系列“命名程序 ...

  8. Landscaping Gym - 101128F (网络流)

    Problem F: Landscaping \[ Time Limit: 1 s \quad Memory Limit: 256 MiB \] 题意 题意是给出一个\(n*m\)的格子,其中一些是低 ...

  9. 04_配置交换机Telnet服务(数通华为)

    1. 网络拓扑: 2. SW1配置:2.1 配置为Access口,vlan 10:[SW1]vlan 10[SW1-GigabitEthernet0/0/1]port link-type access ...

  10. github Actions 使用方法

    http://www.ruanyifeng.com/blog/2019/09/getting-started-with-github-actions.html Actions 是github提供的持续 ...