引言
C语言有可变参数函数
void printf(const char* format, …);
开发中用到printf的地方常常需要做一层封装,这样可以定义自己的开关,从而可以灵活控制打印。以前常用的都是封装一层函数,
void debug_printf(char * fmt,...){ ..........//定义自己的可变参数函数 if( g_debug !=0){ printf(fmt,bufptr); } return 0; }
虽然可以做到通过g_dbug全局变量的设置控制打印。但是即使关闭了打印,在程序执行过程中,依旧需要调用函数debug_printf,增加了压栈和出栈的操作。
if( g_debug !=0)的操作放在函数外面更好,但是如果直接放在外面,则每个调用处都不是一个简单语句,如果能用宏再封装一层不更好,知道最近才知道原来自从C99后就已经支持可变参数的宏定义了。
一个小例子
#define DEBUG_PRINTF(...) printf(__VA_ARGS__)
int main(){
int i = 0;
DEBUG_PRINTF("the var i = %d \n",i);
return 0;
}
保存为test.c后通过编译命令gcc -E test.c可以看到经过预处理后,宏被替换为
#define DEBUG_PRINTF(...) printf(__VA_ARGS__)
int main(){
int i = 0;
printf("the var i = %d \n",i);
return 0;
}
那么引言中提到的函数就可以写为
#define DEBUG_PRINTF(...) \ do{ \ if(g_debug != 0) { \ printf(__VA_ARGS__);\ } \ }while(0)
采用这样定以后,可以做到如果关闭了了打印,那么函数只是做了一个简单的if判断,没有了函数的压栈出栈操作,提高了效率。
详解可变参数宏用法
用法1:#DEBUG_PRINTF(...) printf(__VA_ARGS__)
...代表一个可以变化的参数表。 __VA_ARGS__ 是编译器的保留字段,预处理时把参数传递给宏。当宏的调用展开时,实际的参数就传递给 printf() 了。
1 #define DEBUG_PRINTF(...) printf(__VA_ARGS__)
2 int main()
3 {
4 int i = 0;
5 DEBUG_PRINTF("the value i = %d \n",i);
6 DEBUG_PRINTF("test");
7 return 0;
8 }
[user@Roach study]$ gcc -E test.c
# 1 "test.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "test.c"
int main()
{
int i = 0;
printf("the value i = %d \n",i);
printf("test");
return 0;
}
用法2:#DEBUG_PRINTF(format , ...) printf(format , __VA_ARGS__)
1 #define DEBUG_PRINTF(format,...) printf(format,__VA_ARGS__)
2 int main()
3 {
4 int i = 0;
5 DEBUG_PRINTF("the value i = %d \n",i);
6 DEBUG_PRINTF("test");
7 return 0;
8 }
[user@Roach study]$ gcc -E test.c
# 1 "test.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "test.c"
int main()
{
int i = 0;
printf("the value i = %d \n",i);
printf("test",); //这里出了问题
return 0;
}
在用法2中,要解决变量个数为0的情况需要采用如下方式声明
#DEBUG_PRINTF(format , ...) printf(format , ##__VA_ARGS__)
也就是说用法2的合理声明应该是在__VA_ARGS__之前加连接符##,这样当0个参数时候,就不会实现符号链接了。
其他声明方法:
#DEBUG_PRINTF(format , ...) printf(format , __VA_ARGS__)
和
这样就省去了编译器的保留字__VA_ARGS__,这两种用法没有区别,根据习惯而定。
#DEBUG_PRINTF(format , ...) printf(format , ##__VA_ARGS__)
可以声明为
#DEBUG_PRINTF(format ,args ...) printf(format , args)
和
#DEBUG_PRINTF(format ,args ...) printf(format , ##args)