感谢博主的分享,转自:#、##、__VA_ARGS__和##__VA_ARGS__的作用,##__VA_ARGS__ 总结
1>
一、#用来把参数转换成字符串
例子一:
#define P(A) printf("%s:%d\n",#A,A);
int main(int argc, char **argv)
{
int a = 1, b = 2;
P(a);
P(b);
P(a+b);
system("pause");
}
输出为:
例子二:
#define SQUARE(x) printf("The square of "#x" is %d.\n", ((x)*(x)));
SQUARE(8)
输出的是:The square of 8 is 64
二、##运算符可以用于宏函数的替换部分。这个运算符把两个语言符号组合成单个语言符号,为宏扩展提供了一种连接实际变元的手段
例子一:
#define XNAME(n) x ## n
如果这样使用宏:XNAME(8)
则会被展开成这样:x8
##就是个粘合剂,将前后两部分粘合起来,也就是有“字符化”的意思。但是“##”不能随意粘合任意字符,必须是合法的C语言标示符。在单一的宏定义中,最多可以出现一次“#”或“##”预处理操作符。如果没有指定与“#”或“##”预处理操作符相关的计算次序,则会产生问题。为避免该问题,在单一的宏定义中只能使用其中一种操作符(即,一份“#”或一个“##”,或都不用)。除非非常有必要,否则尽量不要使用“#”和“##”。
三、__VA_ARGS__ 是一个可变参数的宏,很少人知道这个宏,这个可变参数的宏是新的C99规范中新增的,目前似乎只有gcc支持(VC6.0的编译器不支持)。
实现思想就是宏定义中参数列表的最后一个参数为省略号(也就是三个点)。
四、##__VA_ARGS__ 宏前面加上##的作用在于,当可变参数的个数为0时,这里的##起到把前面多余的","去掉的作用,否则会编译出错
一般这个用在调试信息上多一点
例如:
#define my_print1(...) printf(__VA_ARGS__) my_print1("i=%d,j=%d\n",i,j) 正确打印
#define my_print2(fmt,...) printf(fmt,__VA_ARGS__)
my_print1("i=%d,j=%d\n",i,j) 正确打印
my_print1("iiiiiii\n") 编译失败打印,因为扩展出来只有一个参数,至少要两个及以上参数
如果是#define my_print2(fmt,...) printf(fmt,##__VA_ARGS__)
那么
my_print1里面不管是几个参数都能正确打印
#define MODULE_NAME "MY_LIB"
#define error_print(fmt, ...) printf("[ERROR]["MODULE_NAME"](%s|%d)" fmt, __func__, __LINE__, ##__VA_ARGS__)
2>
在嵌入式的交叉编译过程中,经常会用到宏定义控制程序运行模式,或者控制打印模式,提高程序开发和调试效率,比如在某个项目中,设置了几种程序运行模式,控制打印输出:
#define MY_PRINTF_NORMAL 0
#define MY_PRINTF_MUST 1
#define MY_PRINTF_ERROR 2
#define MY_PRINTF_DEBUG 3
//#define MY_PRINTF_LEVEL MY_PRINTF_ERROR
#define MY_PRINTF_LEVEL MY_PRINTF_DEBUG
#define myPrintf(level,format, ...); \
do{ \
if(level <= MY_PRINTF_LEVEL){ \
if(level == MY_PRINTF_NORMAL){ \
os_printf(""format"",##__VA_ARGS__); \
} \
else{ \
os_printf("Level:%d:"format"",level,##__VA_ARGS__); \
} \
} \
}while(0);
#endif
其中涉及到了变参函数(形参数量可变的函数)。
1) 变参函数的实现:
将函数宏的形参列表最后的参数用省略号(...)表示即实现了变参函数。__VA_ARGS__用于在宏替换部分中,表明省略号代表什么。
例如:#define PR(...) printf(__VA_ARGS__);
#include <stdio.h>
#define PR(...) printf(__VA__ARGS__); //Note:需编译器支持__VA__ARGS__
int main(void)
{
int age = 26;
int weight = 75;
float BMI = 26.4;
PR("oh mashuai");
PR("Age:%d, weight:%d,BMI:%d",age,weight,BMI);
}
2)##__VA_ARGS__ 宏前面加上##的作用在于,当可变参数的个数为0时,这里的##起到把前面多余的","去掉的作用,否则会编译出错。
一般这个用在调试信息上多一点
************************************************************ 知识扩展 ****************************************************************************
1) # : 表示将参数转换为字符串输出:
#include <stdio.h>
#define P(A) printf("%s:%d.\r\n",#A,A);
int main()
{
int a=1;
int b=2;
P(a);
P(b);
}
运行结果为:
a:1
b:2
2)## : ##运算符可用于类函数宏的替换部分,也可以用于对象宏的替换部分。主要用于将两个语言符号组成单个语言符号,为宏扩展提供一种连接实际变元的手段;
#include <stdio.h>
#define XNAME(n) X##n //将定元X和变元n组合,列出X1, X2, X3 ...
#define PRINT_XN printf("X"#n"=%d\n",X##n);
int main(void)
{
int XNAME(1)=10;
int XNAME(2)=20;
int X3=30;
PRINT_XN(1);
PRINT_XN(2);
PRINT_XN(3);
}
程序输出为:
X1=10;
X2=20;
X3=30;