宏定义中的#和##

参考:https://mazhuang.org/2014/05/10/numbersign/#标记连接操作-

说明

  • C/C++ 中### 符号用于宏定义;
  • # 作用是将宏定义参数不经任何扩展地转换成字符串常量,所谓拓展包括:
    • 宏定义参数的两边的空格会被忽略;
    • 特殊字符会被加上转义字符;
  • ## 的作用是在宏定义中,将两个部分连接成一个部分,需要注意:
    • 用于连接,所以不能用在首尾;
    • 其前后的空格无意义;

示例

知识点准备:

下面四组其实是等价的:

char* p1 = "Hello," "World!";     // 一个空格
char* p2 = "Hello,"    "World!";  // 多个空格
char* p3 = "Hello,""World!";      // 没有空格
char* p4 = "Hello,World!";        // 一个整串

字符化操作(#)

以MSDN上的例子说明:

#define F abc
#define B def
#define FB(arg) #arg
#define FB1(arg) FB(arg)
qDebug()<<FB(F B);
qDebug()<<FB1(F B);

乍一看,两个输出应该是一样的,其实不然,这里的 # 操作符起作用的时间不一样,实际输出是:

F B
abc def

宏定义在调用时就进行字符串的替换,这里的所谓的不经扩展 就是直接替换,所以,上例中的替换步骤是:

FB(F B) => #F B => "F B"
FB1(F B) => FB(abc def) => #abc def => "abc def"

标记连接操作(##)

以MSDN上的例子说明

#define paster( n ) printf_s( "token" #n " = %d", token##n )
int token9 = 8;//这里例子里是9,我为了区分,改成了8
paster(9);

最后的输出结果是:

token9 = 8

在编译的时候,宏定义替换字符串步骤如下:

  1. paster(9)
  2. printf_s( "token" #9 " = %d", token##9 )
  3. printf_s( "token" "9" " = %d", token9 )
  4. printf_s( "token9" " = %d", token9 )

__VA_ARGS__

__VA_ARGS__ 是一个可变参数宏,在宏中传递参数时,它可以表示传递的 ...,示例如下:

#define test(...) qDebug(__VA_ARGS__)
test(1, 2, 3)	//这里的参数至少有一个

这里有个问题就是,可变参数至少有一个,因为当参数一个都没有时,有个 ,会导致编译错误

##__VA_ARGS__ 可以解决至少有一个参数的问题,其作用是,当参数数目为0时,去掉前面的逗号

#define test(...) qDebug(##__VA_ARGS__)
test()	//这里的不传参也可以
原文地址:https://www.cnblogs.com/sherlock-lin/p/11708151.html