C/C++可变参数,“##

在阅读代码的时候,在一个宏定义语句中,发现了个之前未曾见过的编译器预定义宏:“__VA_ARGS__”。当时,从代码语句中推测它代表宏参数:“…”(本文称之为省略号),依稀记得printf函数声明中有使用这个省略号,大概的意思是表示可变化的参数,但未深入了解。

在网上看了相关文章的介绍,主要涉及了C/C++函数中可变化参数的基础知识,并延伸到宏定义中的可变参数。借这一次的学习,算是对可变化参数有了比较详细的了解,尤其是解开了一直萦绕在头脑中printf函数声明中这个省略号的疑惑。

为更好了解C/C++中可变参数的知识,我从网上摘录了两篇文章,算是自己的一个总结。本篇主要是关于“## __VA_ARGS__”宏的介绍和使用。

C++ Primer Plus 第6版 中文版 清晰有书签PDF+源代码

读C++ Primer 之构造函数陷阱

读C++ Primer 之智能指针

读C++ Primer 之句柄类

C++11 获取系统时间库函数 time since epoch

C++11中正则表达式测试

在GNU C中,宏可以接受可变数目的参数,就象函数一样,例如:

 

1

2

 

#define pr_debug(fmt,arg...) \

printk(KERN_DEBUG fmt, ##arg)

 

用可变参数宏(variadic macros)传递可变参数表
你可能很熟悉在函数中使用可变参数表,如:

 

1

 

void printf(const char* format, ...);

 

直到最近,可变参数表还是只能应用在真正的函数中,不能使用在宏中。

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

 

1

 

#define debug(...) printf(__VA_ARGS__)

 

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

 

1

 

Debug("Y = %d\n", y);

 


而处理器会把宏的调用替换成:

 

1

 

printf("Y = %d\n", y);

 

因为debug()是一个可变参数宏,你能在每一次调用中传递不同数目的参数:

 

1

 

debug("test");  // 一个参数

 


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

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

gcc的预处理提供的可变参数宏定义真是好用:

 

1

2

3

4

5

6

 

#ifdef DEBUG

#define dbgprint(format,args...) \

fprintf(stderr, format, ##args)

#else

#define dbgprint(format,args...)

#endif

 

如此定义之后,代码中就可以用dbgprint了,例如dbgprint("%s", __FILE__);

下面是C99的方法:

 

1

 

#define dgbmsg(fmt,...) printf(fmt,__VA_ARGS__)

 

新的C99规范支持了可变参数的宏
具体使用如下:

以下内容为程序代码:

 

1

2

3

4

5

6

7

8

 

#include <stdarg.h>

#include <stdio.h>

#define LOGSTRINGS(fm, ...) printf(fm,__VA_ARGS__)

int main()

{

LOGSTRINGS("hello, %d ", 10);

return 0;

}

 

但现在似乎只有gcc才支持。
可变参数的宏里的'##'操作说明带有可变参数的宏(Macros with a Variable Number of Arguments)
在1999年版本的ISO C 标准中,宏可以象函数一样,定义时可以带有可变参数。宏的语法和函数的语法类似。下面有个例子:

 

1

 

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

 


这里,'...'指可变参数。这类宏在被调用时,它(这里指'...')被表示成零个或多个符号,包括里面的逗号,一直到到右括弧结束为止。当被调用时,在宏体(macro body)中,那些符号序列集合将代替里面的__VA_ARGS__标识符。更多的信息可以参考CPP手册。
GCC始终支持复杂的宏,它使用一种不同的语法从而可以使你可以给可变参数一个名字,如同其它参数一样。例如下面的例子:

 

1

 

#define debug(format, args...) fprintf (stderr, format, args)

 

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/aac262968650587adf45da5cd1e67dc7.html