C语言宏嵌套展开规则

宏嵌套展开规则

  1. 一般的展开规律像函数的参数一样:先展开参数,再分析函数,即由内向外展开
  2. 当宏中有#运算符的时候,不展开参数
  3. 当宏中有##运算符的时候,先展开函数,再分析参数
  4. ##运算符用于将参数连接到一起,预处理过程把出现在##运算符两侧的参数合并成一个符号,注意不是字符串

###的使用规则

“#”是将宏参数转换为字符串。不管该参数宏是什么,即“原貌”用字符串显示出来。 即将宏参数用双引号“”包裹起来形成一个字符串

#define T(x) #x
int temp = 10;
printf("%s", T(x));

“##”被称为连接符(concatenation),把宏参数与之前的token(参数/字符串空格等)连接起来。例如

#define T(x) x##[2]
int a[5] = {1,2,3,4,5};
printf("%d", T(a));

注意: ##运算的结果 要符合C语言标识符语法(个人理解有可能不对), 上述例子T(a) 展开会报错:[错误] pasting "a" and "[" does not give a valid preprocessing token 原因在于T(a)展开得到a[2] c语言 标示符语法:是_, 大小写字母, 数字且数字不能开头。

宏嵌套

宏嵌套

注意:上图中的 2 和 3 是条件或,只要满足一个条件就会进入流程5。

举例

#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;
}

嵌套宏的展开流程如下:

TO_STRING(PARAM(ADDPARAM(1)))

-> 展开 PARAM:TO_STRING("ADDPARAM(1)")

-> 展开 TO_STRING:TO_STRING1("ADDPARAM(1)")

-> 展开 TO_STRING1:""ADDPARAM(1)""

TO_STRING2(PARAM(ADDPARAM(1)))

-> 展开 TO_STRING2:"PARAM(ADDPARAM(1))"

// example 2
#include <cstdio>
#define TO_STRING2(x) a_##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(TO_STRING2(PARAM(ADDPARAM(1))));
	printf("%s\n",str); //输出: a_PARAM(INT_1)
	return 0;
}

嵌套宏的展开流程如下:

TO_STRING(TO_STRING2(PARAM(ADDPARAM(1))))

-> 展开 TO_STRING2:TO_STRING(a_PARAM(ADDPARAM(1))) //注意此次展开后,PARAM宏名被破坏了,变成了a_PARAM不再是有效的宏名了

-> 展开 ADDPARAM:TO_STRING(a_PARAM(INT_1))

-> 展开 TO_STRING:TO_STRING1(a_PARAM(INT_1))

-> 展开 TO_STRING1:"a_PARAM(INT_1)"

注意:嵌套宏的展开规则与编译器有关,不同的编译器可能对同一个嵌套宏展开不同。

以上测试都是在 VS2010(x86)上

声明:

  1. 博客内容大部分非本人创作, 如有二次引用请注明原作者,及博客链接
  2. 本博客引用知乎:彷徨而立
posted @ 2022-04-06 22:01  月傍山楼水映月  阅读(301)  评论(0编辑  收藏  举报