宏递归终止条件失效疑问:为何YYY宏展开最终结果为ab?
宏递归终止条件失效疑问:为何YYY宏展开最终结果为ab?
嗨,我来帮你把这个宏展开的逻辑掰扯明白,核心就在于C预处理宏的参数展开时机和##运算符的特殊特性,咱们一步步拆解:
先把你定义的宏再贴一遍,方便对照:
#define CAT(A, B) A##B // 直接拼接两个参数,##会抑制参数的预先展开 #define AA(a, b) CAT(a, b) // 调用CAT,参数会先展开再代入宏体 #define YYY(a, b) CAT(a, b) // 和AA的定义完全一致
先拆解CAT(A, A(a, b))的展开流程
- 当调用
CAT(A, A(a,b))时,因为CAT用了##运算符,它的两个参数不会先被展开——说白了就是,A(a,b)不会被当成宏调用处理(你也没定义A这个宏),预处理会直接把A和A(a,b)拼接成AA(a,b)。 - 接下来
AA(a,b)是宏调用,AA的宏体是CAT(a,b),这里AA的参数a和b没被#或##修饰,所以会先展开参数(这里a和b都是普通标识符,不是宏,直接代入),得到CAT(a,b)。 - 最后
CAT(a,b)也是宏调用,预处理会把a和b直接拼接成ab——你写的例子里可能没写完这一步,其实它最终也会走到ab,只是你只列到了CAT(a,b)而已。
再看YYY(A, A(a, b))的展开流程
- 调用
YYY(A, A(a,b))时,YYY的宏体是CAT(a,b),同样,YYY的参数没被#或##修饰,所以先展开参数:第一个参数A是普通标识符,第二个参数A(a,b)也不是宏调用,代入后得到CAT(A, A(a,b))。 - 接下来的步骤就和上面的
CAT(A, A(a,b))完全一致了:先拼成AA(a,b),再展开成CAT(a,b),最后拼接成ab。
你大概率困惑的点:为什么CAT(a,b)能展开成ab?
其实这完全是正常的宏展开流程,CAT是普通的对象式宏,当预处理遇到CAT(a,b)时,会直接触发它的规则——把两个参数拼接起来。这里不存在什么递归终止的问题,因为a和b都不是宏,拼接后的ab也不是宏,所以展开到这里就自然结束了。
简单总结一下:
##运算符的作用是直接拼接令牌,同时会阻止参数的预先展开;- 像
AA、YYY这种封装CAT的宏,会先处理自己的参数,再把结果传给CAT; - 所有宏展开都会层层递进,直到没有可展开的宏为止,所以最终都会得到
ab这个结果。
备注:内容来源于stack exchange,提问作者yunate
相关产品推荐
相关产品推荐

