可变参数宏 , Variadic Macros
时间:2010-06-30 来源:championwxd
这里先讨论可变参数宏。
我们一般在Debug需要打印调试信息的时候,需要可变参数的宏。
一, vc(C99)的复杂宏。
参考msdn(http://msdn2.microsoft.com/en-us/library/ms177415.aspx )。使用这种复杂宏时,省略号是格式控制参数,而标识符__VA_ARGS__用来插入另外的参数。__VA_ARGS__ 将"..." 传递给宏。
例如:
#include <stdio.h>
#define CHECK1(x, ...) if (!(x)) { printf(__VA_ARGS__); }
#define CHECK2(x, ...) if ((x)) { printf(__VA_ARGS__); }
#define CHECK3(...) { printf(__VA_ARGS__); }
int main( )
{
CHECK1(0, "here %s %s %s", "are", "some", "varargs1(1)\n");
CHECK1(1, "here %s %s %s", "are", "some", "varargs1(2)\n"); // won't print
CHECK2(0, "here %s %s %s", "are", "some", "varargs2(3)\n"); // won't print
CHECK2(1, "here %s %s %s", "are", "some", "varargs2(4)\n");
CHECK3("here %s %s %s", "are", "some", "varargs3(5)\n");
return 0;
}
输出为:
here are some varargs1(1)
here are some varargs2(4)
here are some varargs3(5)
二,GCC中的复杂宏
GCC支持C99中的复杂宏,但G++不支持。GCC使用一种不同的语法,给可变参数一个名字,如同其它参数一样。
#define CHECK1(x,format, args...) if(x) { printf (format, args); }
显然这样易于描述而且可读性更强。
三,CHECK("Some messges.")的情况
这时由于宏展开后有个多余的逗号,,将导致编译错误.。为了解决这个问题,CPP使用一个特殊的“##”操作。
#define CHECK(format, ...) printf ( format, ## __VA_ARGS__)
这里,如果可变参数被忽 略或为空,“##”操作将使预处理器去除掉它前面的那个逗号。如果在宏调用时,确实提供了一些可变参数,GNU CPP也会工作正常,它会把这些可变参数放到逗号的后面。
四,类似printf()的技巧
用一个被括弧括起来的 “参数”来定义和调用宏,参数在宏扩展的时候成为类似printf()函数中的格式控制字符串那样的参数列表。
#define CHECK(args) (printf("DEBUG: "), printf(args))
用了括号。
/////////////////////////////////////////////////
今天来说说宏。什么? 宏也能可变参数?是的,你没有听错,带参数的宏和函数一样,同样支持可变参数。下面通过一个小程序加以说明。
#include
#include
#define OUTSCREEN(msg, ...) printf(msg,__VA_ARGS__)
int main(int argc, char* argv[])
{
OUTSCREEN("Hello World!n%s", "__This is a MACRO!n");
return 0;
}
这个可变参数的 宏是新的C99规范中新增的,目前似乎只有gcc支持(VC6.0的编译器不支持)。
#define OUTSCREEN(msg, ...) printf(msg, __VA_ARGS__)
int main(int argc, char* argv[])
{
OUTSCREEN("Hello World!n%s", "__This is a MACRO!n");
return 0;
}
假如我们将上面的 代码稍作一下修改,变成下面的样子。
#define OUTSCREEN(msg, ...) printf(msg, __VA_ARGS__)
int main(int argc, char* argv[])
{
OUTSCREEN("Hello World!");
return 0;
}
注意我仅仅是将main函数里的OUTSCREEN做了修改,这时可变参 数的个数为0了。但是编译的时候gcc却报错:
In function `main':
error: parse error before ')' token
什么原因导致出错 呢?把宏展开一下看看,原来是","惹得祸。那么这种参数个数可以为0的宏要怎么写呢?C99的规范没有定义这个,gcc对此做了扩展。重新定义OUTSCREEN宏如下:
#define OUTSCREEN(msg, ...) printf(msg, ##__VA_ARGS__)
当可变参数的个数 为0时, 这里的##起到把前面多余的","去掉,实际上变成了printf(msg),这样编译就能通过了。
另外,__VA_ARGS__这个宏实在不利于 记忆,gcc对此做了扩展,另一种可接受的定义方法为:
#define OUTSCREEN(msg, args...) printf(msg, ##args)