类函数宏嵌套调用的C预处理器展开规则疑问
C 互调宏展开规则常见误解解答
首先给出你提到的代码片段:
#define FOO() BAR #define BAR() FOO FOO()()()
核心理解疏漏
你对宏展开时的禁用规则范围理解有误:C99 6.10.3.4p2 规定的「展开过程中忽略当前宏名称」,仅适用于本次宏展开生成的替换列表本身的标记,不包括替换后紧跟的其他源文件标记,也不会作用于其他宏展开生成的标记。也就是说,只有在当前正在展开的宏的替换列表扫描过程中,出现和当前宏同名的标记才会被跳过,其他场景下的同名宏标记都可以正常识别展开。
完整展开步骤拆解
我们按标准规则一步步走整个展开流程:
- 初始预处理标记序列:
FOO()()() - 匹配到第一个宏调用
FOO(),将FOO()三个标记替换为BAR,得到新序列:BAR()()。此时仅在扫描BAR这个FOO的替换标记时,FOO会被禁用,后续的括号属于源文件剩余标记,不受FOO禁用规则影响。 - 重扫新序列,匹配到
BAR()宏调用,将BAR()替换为FOO,得到新序列:FOO()。此时仅在扫描FOO这个BAR的替换标记时,BAR会被禁用,FOO本身没有被当前流程禁用。 - 再次重扫新序列,匹配到
FOO()宏调用,该FOO是BAR展开生成的标记,不属于最初FOO展开的替换列表范围,因此可以正常展开为BAR,得到最终结果。
补充说明
你之前误以为只要是最初FOO展开间接产生的FOO标记都会被永久禁用,这是对标准规则的扩大化理解。标准的禁用规则本质是为了避免无限递归展开,仅限制同一个宏在自己的替换列表中直接/间接调用自己,不会限制不同宏交替展开时重新调用外层宏。
内容的提问来源于stack exchange,提问作者koorkevani
相关产品推荐
相关产品推荐

