You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

令牌连接运算符##与递归宏展开禁止规则的交互及边界影响

标准规则

关于宏展开的重新扫描阶段(在#/##处理和参数替换之后),C17草案6.10.3.4 ¶2中的标准规定如下:

如果在对替换列表的扫描过程中(不包括源文件其余部分的预处理令牌)发现正在被替换的宏的名称,则不进行替换。此外,如果任何嵌套替换遇到正在被替换的宏的名称,也不进行替换。这些未被替换的宏名称预处理令牌即使之后在其他原本会进行替换的上下文环境中被(重新)检查,也不再可供进一步替换。

借此机会,我总结一下对象式或函数式宏M的宏替换与#/##处理及参数替换的交互方式:

  1. 位于#之后或与##相邻的参数将被原样替换(可能作为占位符令牌),然后由#和##处理。
    • 注意,标准未指定#和##的相对求值顺序,这是否会产生影响目前尚不明确。
  2. 对于其他每个参数,首先对其对应的实参进行完全宏展开,然后用展开结果替换该参数。
    • 这些实参的宏展开过程如同它们独立存在一样,即替换列表中参数后的括号内的函数参数不会被考虑,这与作为参数实参一部分提供的函数参数不同。
  3. 删除所有由##产生的占位符令牌。
  4. 对生成的令牌序列S以及源文件中所有后续的预处理令牌进行重新扫描,以查找更多待求值的宏。
    • 在此过程中,S内部或S的展开结果中出现的M的后续实例将不会被展开,即使在其他上下文中被检查也是如此。

(此算法描述与标准中的描述并不完全相同,但至少就本文目的而言,二者足够等价。)

问题

令牌连接运算符##的应用与递归宏展开禁止规则之间存在怎样的交互?具体而言,它如何影响某些递归展开被阻止的区域的边界?


本站存在一个类似问题:Is a repeated macro invocation via token concatenation unspecified behavior?
说明:

  • 其示例较为复杂。
  • 其回答未深入细节。
  • 我的回答(如下)尝试展示详细的分步求值过程。
  • 我的回答(如下)展示了两个理论上应被同等处理但实际并非如此的宏展开案例。

内容的提问来源于stack exchange,提问作者Lover of Structure

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 05:09:50