CC++宏定义的可变参数详细解析(转)
转⾃:
编写代码的过程中,经常会输出⼀些调试信息到屏幕上,⼀般会调⽤printf这类的函数。
但是当调试解决之后,我们需要⼿⼯将这些地⽅删除或者注释掉。
最近在看《Linux C编程⼀站式学习》这本书,就想到⼀个⽅法:fprintf格式
代码如下:
void myprintf(char* fmt, ...)
{
}
#ifdef DEBUG
#define printf(fmt, ) myprintf(fmt, ##args)
#endif
调试阶段带着DEBUG调试,正式上线就可以把printf变成⼀个空函数了。
这样做的⼀个潜在风险是可能会导致默写glib函数需要调⽤printf输出错误log也给取消掉了。
令⼈欣慰的是,⼤部分glib调⽤的应该是fprintf。
虽然问题解决了,但是我对以及##args还是不太了解。上⽹了些gcc⼿册的资料如下:
带有可变参数的宏(Macros with a Variable Number of Arguments)
在1999年版本的ISO C 标准中,宏可以象函数⼀样,定义时可以带有可变参数。宏的语法和函数的语法类似。
下⾯有个例⼦:
代码如下:
#define debug(format, ...) fprintf (stderr, format, __VA_ARGS__)
这⾥,‘…'指可变参数。这类宏在被调⽤时,它(这⾥指‘…')被表⽰成零个或多个符号,包括⾥⾯的逗号,⼀直到到右括弧结束为⽌。当被调⽤时,在宏体(macro body)中,那些符号序列集合将代替⾥⾯的__VA_ARGS__标识符。更多的信息可以参考CPP⼿册。
GCC始终⽀持复杂的宏,它使⽤⼀种不同的语法从⽽可以使你可以给可变参数⼀个名字,如同其它参数⼀样。例如下⾯的例⼦:
代码如下:
#define debug(format, ) fprintf (stderr, format, args)
这和上⾯举的那个ISO C定义的宏例⼦是完全⼀样的,但是这么写可读性更强并且更容易进⾏描述。
GNU CPP还有两种更复杂的宏扩展,⽀持上⾯两种格式的定义格式。
在标准C⾥,你不能省略可变参数,但是你却可以给它传递⼀个空的参数。例如,下⾯的宏调⽤在ISO C⾥是⾮法的,因为字符串后⾯没有逗号:
代码如下:
debug ("A message")
GNU CPP在这种情况下可以让你完全的忽略可变参数。在上⾯的例⼦中,编译器仍然会有问题(complain),因为宏展开后,⾥⾯的字符串后⾯会有个多余的逗号。
为了解决这个问题,CPP使⽤⼀个特殊的‘##'操作。
书写格式为:
代码如下:
#define debug(format, ...) fprintf (stderr, format, ## __VA_ARGS__)
这⾥,如果可变参数被忽略或为空,‘##'操作将使预处理器(preprocessor)去除掉它前⾯的那个逗号。如果你在宏调⽤时,确实提供了⼀些可变参数,GNU CPP也会⼯作正常,它会把这些可变参数放到逗号的后⾯。象其它的pasted macro参数⼀样,这些参数不是宏的扩展。
具体参见《Linux C编程⼀站式学习》,顺便夸赞下这本书,写的很好!

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。