在C语言的标准库中,printf、scanf、sscanf、sprintf、sscanf这些标准库的输入输出函数,参数都是可变的。在调试程序时,我们可能希望定义一个参数可变的输出函数来记录日志,那么用可变参数的宏是一个不错的选择。

在C99中规定宏也可以像函数一样带可变的参数,如:

#define LOG(format, ...) fprintf(stdout, format, __VA_ARGS__)

其中,...表示可变参数列表,__VA_ARGS__在预处理中,会被实际的参数集(实参列表)所替换。

同时gcc还支持带可以变参数名的方式(注意:VC不支持):

#define LOG(format, args...) fprintf(stdout, format, args)

同样,args在预处理过程中,会被实际的参数集所替换。其用法和上面的方式一样,只是参数的符号有变。

需要注意的是,上述两种方式的可变参数不能省略,尽管可以传一个空参数进去。说到这里,有必要提一下“##”连接符号的用法,“##”的作用是对token进行连接,上例中format,args,__VA_ARGS都可以看作是token,如果token为空,“##”则不进行连接,所以允许省略可变参数。对上述2个示例的改造:

#define LOG(format, ...) fprintf(stdout, format, ##__VA_ARGS__)
#define LOG(format, args...) fprintf(stdout, format, ##args)

即然参数可以省略,那么用宏定义一个开关,实现一个输出日志的函数就简单了:

#ifdef DEBUG
#define LOG(format, ...) fprintf(stdout, ">>>>>" format "<<<<", ##__VA_ARGS__)
#else
#define LOG(format, ...)
#endif

example

#include "stdio.h"

#define LOG_TYPE1(format, ...) do{ 		\
printf(format, __VA_ARGS__); \
\
} while(0) #define LOG_TYPE2(format, args...) do{ \
printf(format, args); \
\
} while(0) #define LOG_TYPE3(format, ...) do{ \
printf(format, ##__VA_ARGS__); \
\
} while(0) #define LOG_TYPE4(format, args...) do{ \
printf(format, ##args); \
\
} while(0) #define LOG(x) printf("LOG "#x" %d \n", x); int value = 10; int main()
{ printf("hello world. \n"); //LOG_TYPE1("hello %d \n"); error
LOG_TYPE1("hello %d \n", 1); //LOG_TYPE2("hello \n"); error
LOG_TYPE2("hello %d \n", 2); LOG_TYPE3("hello 3\n");
LOG_TYPE3("hello %d\n", 3); LOG_TYPE4("hello 4\n");
LOG_TYPE4("hello %d\n", 4); LOG(10);
LOG(value); return 0;
}

C 语言 define 变参__VA_ARGS__使用的更多相关文章

  1. C语言可变参实现参数累加返回

    C语言可变参的作用真的是非常大,自从发表了可变参如何实现printf,fprintf,sprintf的文章以来,便有不少博友私信问我实现的机制,我也解释了相关的知识点.今天,我们借着这个机会,再来举一 ...

  2. c语言可变参

    一.什么是可变参数 在C语言编程中有时会遇到一些参数个数可变的函数,例如printf(),scanf()函数,其函数原型为: int printf(const char* format,…),int ...

  3. C语言-define 与do{}while(0)

    问题引出: 我们都知道宏定义#define只是简单替换,所以遇到复杂的带参数宏,必须很小心的为需要的参数加上括号“()”:同样碰到复杂的多条语句替代,虽然加{}可以将其封装成一个整体,但同时又有另一个 ...

  4. c语言#define用法

    01 作用域 预编译作用域限本文全局,如: a.c中定义:#define TEST 1 b.c中定义:#define TEST 2 两者编译不交叉,互不影响. 若需#define TEST作用于a.c ...

  5. C语言define 可以提高程序运行的速度

    define的优缺点 优点 提高了程序的可读性,同时也方便进行修改: 提高程序的运行效率:使用带参的宏定义既可完成函数调用的功能,又能避免函数的出栈与入栈操作,减少系统开销,提高运行效率: 3.宏是由 ...

  6. c语言define和typedef区别和使用

    define完全可以理解替换,typedef代表别名.听着差不多的意思,那2者区别在哪? 先来个简单例子查看基本使用. //define和typedef区别 #define DB double //替 ...

  7. C语言 define实现的宏函数汇总

    最大值,最小值 #define MAX( x, y ) ( (x) > (y) ? (x) : (y) )#define MIN( x, y ) ( (x) < (y) ? (x) : ( ...

  8. C语言的变参列表 va_list

    1. va_list的基本原理和用法 #include<stdio.h> #include<stdarg.h> void func(int i,char *ch,...){ / ...

  9. 【C语言】中的版本规范(C89 C99等)

    C语言中的版本 一.相关基础知识 ISO:国际标准化组织(International Organization for Standardization,ISO)简称ISO,是一个全球性的非政府组织,是 ...

随机推荐

  1. swift3.0 屏幕截图并且保存到本地相册

    所要截取的对象 var bg_view: UIView! 截取并且保存的代码如下 UIGraphicsBeginImageContextWithOptions(bg_view.frame.size, ...

  2. HTML中的target标记

    HTML:target=_blank -- 在新窗口中打开链接 _parent -- 在父窗体中打开链接 _self -- 在当前窗体打开链接,此为默认值 _top -- 在当前窗体打开链接,并替换当 ...

  3. C#+HtmlAgilityPack—>糗事百科桌面版V2.0

    最近在浏览以前自己上传的源码,发现在糗事百科桌面端源码评论区中,有人说现在程序不能用了.查看了一下源码运行情况,发现是正则表达式解析问题.由于糗百的网页版链接和网页格式稍有变化,导致解释失败.虽然可以 ...

  4. js的基础要点

    javascript作为一种脚本语言可以放在html页面中任何位置,但是浏览器解释html时是按先后顺序的,所以前面的script就先被执行.比如进行页面显示初始化的js必须放在head里面,因为初始 ...

  5. css 定位功能position

    Static 定位 HTML元素的默认值,即没有定位,元素出现在正常的流中.静态定位的元素不会受到top, bottom, left, right影响. 相对定位Relative相对定位元素的定位是相 ...

  6. 正则表达式(即:匹配模式Pattern)

    通过学习<正则表达式-Regular-Expression-Tutorial.pdf>这份文档,对正则表达式有了很好的了解,原因只有1个--这份文档写得太好了. 它的下载地址是:http: ...

  7. Mybatis(二)

    1 Mybatis映射文件--增删改查 POJO类 package cn.demo1; import org.apache.ibatis.type.Alias; /** * 描述:POJO */ @A ...

  8. python——内置函数和匿名函数

    内置函数 接下来,我们就一起来看看python里的内置函数.截止到python版本3.6.2,现在python一共为我们提供了68个内置函数.它们就是python提供给你直接可以拿来使用的所有函数.这 ...

  9. python自动化运维四:nmap端口扫描

    p { margin-bottom: 0.25cm; line-height: 120% } a:link { } 端口扫描器: Python的第三方模块python-nmap可以实现高效的端口扫描. ...

  10. webpack打包体积优化

    优化: 1:外部引入模块(cdn)     如 jquery,zepto,d3, bootstrap这些固定的lib 使用cdn直接引用就可以,没有必要打包到build,有效利用302. 2:图标优化 ...