为何同签名的可变参数宏TRACE编译失败而ASSERT正常?
问题
我定义了两个可变参数宏,其中ASSERT可正常编译,但TRACE编译失败:
#define ASSERT(x, ...) assert_log(x, __FILE__, __LINE__, __VA_ARGS__) #define TRACE (x, ...) trace(x, __FILE__, __LINE__, __VA_ARGS__)
报错信息:
libs/defs.h:16:71: error: __VA_ARGS__ can only appear in the expansion of a C99 variadic macro [-Werror] 16 | #define TRACE (x, ...) trace(x, __FILE__, __LINE__, __VA_ARGS__) | ^
两个宏对应的函数签名一致:
void assert_log(int, const char*, int, const char* , ...); void trace(int, const char*, int, const char* , ...);
编译选项:
CFLAGS= \ -Wextra \ -Werror \ -Wall \ -Wfloat-equal \ -Wundef \ -Wshadow \ -Wcast-align \ -Wstrict-prototypes \ -Wswitch-enum \ -Wformat=2 \ -Werror=pointer-arith \ -Wuninitialized \ -pedantic \ -std=c17 \ -DDEBUG=1 \ -g \ -Og
既然函数签名相同,我无法理解GCC为何报错?
问题原因与解决方法
问题出在TRACE宏的定义语法上:#define TRACE (x, ...) 中TRACE和括号之间多了一个空格。
C语言中,宏定义的名称和参数列表的左括号必须紧挨着,不能有空格。如果加了空格,预处理器会把TRACE解析成一个无参数宏,后面的(x, ...)会被当成宏展开内容的一部分,此时__VA_ARGS__并不处于可变参数宏的上下文里,自然触发编译错误。
对比ASSERT的定义#define ASSERT(x, ...),名称和括号没有空格,符合可变参数宏的语法要求,所以能正常编译。
只需要去掉TRACE和括号之间的空格,修正后的宏定义如下:
#define TRACE(x, ...) trace(x, __FILE__, __LINE__, __VA_ARGS__)
内容的提问来源于stack exchange,提问作者Denis
相关产品推荐
相关产品推荐

