宏的展开与嵌套

宏的展开与嵌套

宏嵌套的展开规则

C语言中,宏是在预编译时用宏体内容**“文本替换”**代码中的宏名的。

“#”和“##”的使用规则:

一般的展开规律像函数的参数一样:
先展开参数,再分析函数,即由内向外展开 。

当宏中有#运算符的时候:不展开参数
当宏中有##运算符的时候:先展开函数,再分析参数

##运算符用于将参数连接到一起:
预处理过程把出现在##运算符两侧的参数合并成一个符号,注意不是字符串

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

例如

#define T(x) #x
int temp = 10;
cout<<T(temp)<<endl;//输出 temp 而不是 10
// T(temp) -> "temp"  (将宏参数用双引号包含起来形成一个字符串)
“##”被称为连接符(concatenation),把宏参数与之前的token(参数/字符串空格等)连接起来。例如

#define T(x) x##[2]
int a[5] = {1,2,3,4,5};
cout<<T(a)<<endl; //输出 3 即 a[2]
宏的常见展开错误:
// 1. 宏参数在宏体中未加括号包裹起来
#define T(a)  a*10
int a  = 1;
cout<<T(a+1)<<endl; //输出 11 而非20

// 2. 整个宏体内容未加括号包裹起来
#define T(x)  x+1
cout<<10*T(1)<<endl; //输出 11 而非20
解决办法:

在宏定义中,将参数加上括号,这样在替换时保证括号内的表达式优先运算。
//即把传进来的参数当作完全的一个整体,防止优先级问题,参数被分开。
利用括号将整个宏定义的内容括起来,保证整个宏定义中的表达式优先运算。
//同样将宏定义表达式作为一个整体,防止外部优先级,将表达式分开。

宏嵌套

宏嵌套是宏使用的难点,也是易错点。下面我将宏嵌套的展开规则用流程图来说明一下:

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

// 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;
}
上例中两个嵌套宏的展开流程如下:

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)"

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

转载于https://zhuanlan.zhihu.com/p/344240420

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值