可变参数可能会出现在两个地方:
1,函数中
2,函数式宏中
##运算符的另外一种用法就是出现在函数式宏中。以下是书上原话:
宏定义中可变参数的部分用__VA_ARGS__表示。在宏展开时,和…对应的几个实参可以看成一个实参来替换掉__VA_ARGS__。
GCC有一种扩展用法,如果##运算符用在__VA_ARGS__前面,除了起连接Token的作用之外还有一种特殊的用法,例如内核代码net/netfilter/nf_conntrack_proto_sctp.c中的:
#define DEBUGP(format,…) printk(format, ## __VA_ARGS__)
内核函数printk类似于printf,也带有格式化字符串和可变参数,由于内核不能调用libc的库函数,所以另外实现了这样一个打印函数。这函数式宏定义的可以这样调用:DEBUG(“info no. %d”, 1), 也可以这样调用:DEBUG(“info”)。后者相当于可变参数部分传了一个空参数,但展开之后并不是printk(“info”,),而是printk(“info”),当__VA_ARGS__是空码数时,##运行算符把它前面的逗号“吃”掉了。
例:
#include<stdio.h>
#defineDEBUG(format, ...) do{\
/*我自己的理解*/\
/*注意此时若可变参数部分为空,即__VA_ARGS__为空,则下面心编译后为printf(format);*/\
/*即##会吃掉它前面的逗号,否则##不会做任何事*/\
printf(format,## __VA_ARGS__); \
}while(0)
intmain(){
DEBUG("2011-8-19 20:22\n");
return 0;
}
这个仅供娱乐:
#include<stdio.h>
#defineSTR(s) VAL(s)
#defineVAL(s) # s
#defineDEBUG(format, ...) do{\
/*我自己的理解*/\
/*注意此时若可变参数部分为空,即__VA_ARGS__为空,则下面心编译后为printf(format);*/\
/*即##会吃掉它前面的逗号,否则##不会做任何事*/\
printf(format,## __VA_ARGS__); \
}while(0)
/*此函数式宏不调用时至少传一个参数,因为运算符# 后面一定要有参数*/
#defineLKVARGS(...) printf("%s\n",VAL(__VA_ARGS__));
intmain(void){
char *ptr_s = "world";
char *ptr_name = "xiaoqian";
DEBUG("2011-8-19 20:22\n");
DEBUG("hello %s, I am %s\n", ptr_s, ptr_name);
LKVARGS("arg1", "arg2","arg3");
return 0;
}