c语言可变长参数传递问题
一、问题描述
C语言中的函数提供了一种可变长参数机制,这个机制使得我们在操作的时候充分自定义自己的功能,例如使用最多的printf
函数:
printf("%s: %d", "HelloWorld", 10);
它的函数声明为:
printf(const char *fmt, ...);
其中的...
就代表不固定的参数,使用起来十分方便。但是在函数嵌套的时候,不能直接使用...
来占位,例如:
#define logerr(s, ...) do { fprintf(stderr, s, ...); } while (0)
编译时就会报错:
va_args.c:4:50: error: expected expression before ‘...’ token
#define logerr(s, ...) do { fprintf(stderr, "s", ...); } while (0)
如果要嵌套使用,需要通过宏__VA_ARGS__
完成:
#define logerr(s, ...) do { fprintf(stderr, s, __VA_ARGS__); } while (0)
二、参数个数为0的问题
使用上面的方法,参数个数为0的时候编译也会报错:
#define logdbg(s, ...) do { fprintf(stderr, s, __VA_ARGS__); } while (0)
int main() {
logdbg("HelloWorld\n");
return 0;
}
编译报错:
> 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函数里面的代码变成了:
> 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__
前面加上##
,例如:
#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;
}
编译运行:
> make va_args
gcc va_args.c -o debug/va_args
> ./debug/va_args
HelloWorld
HelloWorld
此处评论已关闭