1.使用#运算符。出现在宏定义中的#运算符把跟在其后的参数转换成一个字符串。有时把这种用法的#称为字符串化运算符
参考连接:https://zhuanlan.zhihu.com/p/344240420
1.1 明白什么是参数宏:
1.嵌套宏的一些展开规则:
1.一般的展开规律(没有遇到 # )和函数一样,先展开参数,再分析函数,即由内向外展开;
2.如果遇到 # 运算符,不展开参数;
3.如果遇到 ## 运算符,先展开函数,再分析参数;
4.##运算符用于将参数连接到一起,预处理过程把出现在##运算符两侧的参数合并成一个符号,注意不是字符串。
2. # 和 ## 的区别:
1. # 是将 宏参数 转化为字符串,无论 宏参数 是什么均用字符显示出来;
例如:#define Tem(M) #M_string
int temp = 100;
cout << Tem(temp) << endl; // 显示: temp_string
2. ## 被称为连接符(concatenation),把宏参数与之前的token(参数/字符串空格等)连接起来。例如:
#define T(x) x##[2]
int a[5] = {1,2,3,4,5};
cout<<T(a)<<endl; //输出 3 即 a[2]
3.展开思路:
3.举例(重要):
// example 1
#include <cstdio>
#define TO_STRING2(x) #x
#define TO_STRING1(x) #x
#define TO_STRING(x) TO_STRING1(x)
#define PARAM(x) #x
#define ADDPARAM(x) INT_##x
int main()
{
const char *str = TO_STRING(PARAM(ADDPARAM(1)));
printf("%s\n",str); //输出: "ADDPARAM(1)"
str = TO_STRING2(PARAM(ADDPARAM(1)));
printf("%s\n",str); //输出: PARAM(ADDPARAM(1))
return 0;
}
上面两个宏的展开流程如下:
1.TO_STRING(PARAM(ADDPARAM(1)))
TO_STRING(PARAM(ADDPARAM(1)))
-> 展开 PARAM:TO_STRING("ADDPARAM(1)")
-> 展开 TO_STRING:TO_STRING1("ADDPARAM(1)")
-> 展开 TO_STRING1:"\"ADDPARAM(1)\""
解析:
1. 找到宏 #define TO_STRING(x) #x 发现这个宏没有运算符#,对应嵌套宏的展开规则,需要展开参数,即展开 PARAM(ADDPARAM(1));
2.找到宏 #define PARAM(x) #x 发现这个宏有运算符#,对应嵌套宏的展开规则,则无需展开参数,即:
-->展开 PARAM:PARAM(ADDPARAM(1)) 展开成 "ADDPARAM(1)"
3.展开 PARAM 之后,再回到宏 TO_STRING(x) 即变成了TO_STRING1(x) -->
TO_STRING1(
"ADDPARAM(1)"
)
4.找到宏#define TO_STRING1(x) #x 发现这个宏有运算符 #,对应嵌套宏的展开规则,不需要展开参数;
-->展开
TO_STRING1(
"ADDPARAM(1)"
) 展开成 "\"ADDPARAM(1)\""
5.最后输出:"ADDPARAM(1)"
2.TO_STRING2(PARAM(ADDPARAM(1)))
-> 展开 TO_STRING2:"PARAM(ADDPARAM(1))"
解析:找到宏
#define TO_STRING2(x) #x 发现有运算符# 对应嵌套宏的展开规则,则无需展开参数:
1.TO_STRING2(PARAM(ADDPARAM(1))) 展开成
"PARAM(ADDPARAM(1))" (注意这个"" 其实是没有的,到输出的时候 "" 需要去掉,这里只是为了方便说明)
2.最后输出:
PARAM(ADDPARAM(1))
对于##的展开情况如下: