一、问题描述
C语言中的函数提供了一种可变长参数机制,这个机制使得我们在操作的时候充分自定义自己的功能,例如使用最多的printf
函数:
1 |
printf("%s: %d", "HelloWorld", 10); |
它的函数声明为:printf(const char *fmt, ...);
,其中的...
就代表不固定的参数,使用起来十分方便。但是在函数嵌套的时候,不能直接使用...
来传递,例如代码
1 |
#define logerr(s, ...) do { fprintf(stderr, s, ...); } while (0) |
编译时就会报错:
1 2 |
va_args.c:4:50: error: expected expression before ‘...’ token #define logerr(s, ...) do { fprintf(stderr, "s", ...); } while (0) |
如果要嵌套使用,需要通过宏__VA_ARGS__
完成:
1 |
#define logerr(s, ...) do { fprintf(stderr, s, __VA_ARGS__); } while (0) |
二、参数个数为0的问题
使用上面的方法,参数个数为0的时候编译也会报错:
1 2 3 4 5 6 |
#define logdbg(s, ...) do { fprintf(stderr, s, __VA_ARGS__); } while (0) int main() { logdbg("HelloWorld\n"); return 0; } |
编译报错:
1 2 3 4 |
> gcc va_args.c -o debug/va_args va_args.c: In function ‘main’: va_args.c:5:59: error: expected expression before ‘)’ token #define logdbg(s, ...) do { fprintf(stderr, s, __VA_ARGS__); } while (0) |
原因是因为参数个数零,预编译后main函数里面的代码变成了:
1 2 3 4 5 6 7 8 9 10 11 |
> gcc -E va_args.c | tail int main() { const char *msg = "HelloWorld"; do { fprintf( # 10 "va_args.c" 3 4 stderr # 10 "va_args.c" , "HelloWorld\n", ); } while (0); return 0; } |
可以看到:fprintf
函数的最后是"HelloWorld", );
,最后一个逗号和括号之间没有数据,语法不通过。
解决方案
在__VA_ARGS__
前面加上##
,例如:
1 2 3 4 5 6 7 8 9 10 11 12 |
#include <stdio.h> #include <stdarg.h> #define logerr(s, ...) do { fprintf(stderr, s, ##__VA_ARGS__); } while (0) #define logdbg(s, ...) do { fprintf(stderr, s, ##__VA_ARGS__); } while (0) int main() { const char *msg = "HelloWorld"; logerr("%s\n", msg); logdbg("HelloWorld\n"); return 0; } |
编译运行:
1 2 3 4 5 |
> make va_args gcc va_args.c -o debug/va_args > ./debug/va_args HelloWorld HelloWorld |
评论