gcc编译器宏定义做了许多扩展,支持宏定义可变参数列表。
1. 在不支持可变参数列表之前,为了写支持不同参数的打印宏定义,打印Log的宏定义可能会这样写:
#define Log1(format, args1) printf(format, args1)
#define Log2(format, args1, args2) printf(format, args1, args2)
#define Log3(format, args1, args2, args3) printf(format, args1, args2, args3)
Log1("%s\n", "a");
Log2("%s %s\n", "a", "b");
Log3("%s %s %s\n", "a", "b", "c");这种写法弊端很明显,只要参数个数不一样,就得多写一个宏定义。2. 在不支持可变参数列表之前,在很多源代码里面经常看到如下写法:
#define Log(args) printf args
Log(("%s %s\n", "a", "b"));
这样做相当于对printf做了简单的替换,只是语义上更好理解一点而已。
3. C99之前gcc对宏定义可变参数列表的支持。
#define Log(format, args...) printf(format, ##args)
Log("%s\n", "abc");
Log("%s %d\n", "abc", 10);
Log("%s %d %d\n", "abc", 10, 10);现在我们可以用类似函数可变参数列表的方式作用于宏定义
4. C99以后gcc对宏定义可变参数列表的支持。
#define Log(format, ...) printf(format, ##__VA_ARGS__)
Log("%s\n", "abc");
Log("%s %d\n", "abc", 10);
Log("%s %d %d\n", "abc", 10, 10);C99以后,gcc在在预处理阶段,专门用可变参数替换__VA_ARGS__宏定义,__VA_ARGS__为gcc自定义的宏定义。
5. 细心地同学可能会注意到在可变参数列表中使用了##,为什么要用##呢?
这是因为宏定义只是在预处理阶段简单地替换, 如果可变参数列表为空,宏定义将会多出一个","
#define Log(format, ...) printf(format, __VA_ARGS__)
Log("abc"); // 替换后为 printf("abc", ); 这种写法会造成编译错误,gcc用##解决该问题: 如果可变参数列表为空,就会将紧挨着")"的“,”去掉。
本文介绍了GCC编译器对宏定义可变参数列表的支持,从C99之前的简单替换到C99之后的扩展特性,并讨论了##运算符在处理空参数列表时的作用。
716

被折叠的 条评论
为什么被折叠?



