c - 类函数宏的嵌套调用
问题描述
考虑以下代码片段:
#define FOO() BAR
#define BAR() FOO
FOO()()()
C 标准告诉我们,在参数替换等之后,宏调用产生的预处理标记被重新扫描以获取更多宏名称,忽略生成它们的宏的名称 (c99, 6.10.3.4p1-2)
因此,我希望预处理器将片段转换为BAR()()
, 然后FOO()
,然后停止,因为令牌FOO
是宏的结果FOO
,并且不被识别为宏名称。
但是 GCC 和 clang 都给了我结果BAR
,表明它实际上是在扩大一次。FOO
仅当宏的调用“发生”在参数列表(不再忽略宏名称)而不是宏名称本身时,这才有意义。这是非常不直观的,我发现标准中没有提到它。我错过了什么?
提前致谢!
解决方案
以下是 C 标准的相关段落:
6.10.3.4 重新扫描和进一步更换
1 在替换列表中的所有参数都已被替换并且 # 和 ## 处理已经发生后,所有 placemarker 预处理标记都将被删除。然后重新扫描生成的预处理标记序列以及源文件的所有后续预处理标记,以替换更多宏名称。
2 如果在替换列表的扫描过程中找到被替换的宏的名称(不包括源文件的其余预处理标记),则不会替换它。此外,如果任何嵌套替换遇到被替换的宏的名称,它不会被替换。这些未替换的宏名称预处理标记不再可用于进一步替换,即使它们稍后在该宏名称预处理标记将被替换的上下文中进行(重新)检查。
3 所得到的完全被宏替换的预处理标记序列即使与预处理指令相似,也不会作为预处理指令处理,但其中的所有 pragma 一元运算符表达式随后将按照下面 6.10.9 中的规定进行处理。
例如,如果你写了
#define QQ() QQ
QQ()()()
扩展只是QQ()()
因为根据 2) 在QQ
替换列表的扫描过程中发现时,它没有被扩展。
相反,在您的示例中,FOO
在 , 的替换列表中未找到FOO()
,BAR
随后()
导致它被扩展,反过来又BAR
在 的替换列表中找不到BAR()
,但FOO
最后一组()
再次被扩展。
短语如果任何嵌套替换遇到被替换的宏的名称,它不会被替换是指在宏参数扩展期间发生的替换。在您的示例中,替换是迭代发生的,而不是递归发生的,因此额外的 set()
将导致进一步扩展。
推荐阅读
- r - dplyr: Handing over multiple variables to group_by in a function
- python - 定义内部有变量的lambda函数时,如何防止在更改变量时更改函数?
- python - 如何通过 Anaconda 安装安装 winsound 库
- android - 如何为下载的 Android 项目创建应用程序配置
- reactjs - 无法在 Todo 应用程序中输入 React 输入文本字段
- javascript - 使用没有变量声明的异步迭代
- c++ - G ++:不使用掩码向量化循环
- java - 如何从 @LdapIdentityStoreDefinition 的环境属性/Payara 容器中读取 bindDnPassword 值
- shell - 为什么这个 compdef 错误消息指的是?
- vagrant - Vagrant 不同步文件