您可以使用以下构造迭代预处理器序列:
\n#define A() B\n#define B() A\nA()()()()()\nRun Code Online (Sandbox Code Playgroud)\n扩展到B大多数编译器/预处理器:clang、gcc、tcc、chibicc、SDCC(我无法测试 msvc,因为它在 godbolt 上不起作用,但如果你想测试它,请确保使用该标志/Zc:preprocessor,因为否则预处理器将不合格)。
阅读6.10.3.4似乎表明, 的扩展B发生在 内部A,这将导致 的第二次扩展A不会发生,而是会被漆成蓝色,并且扩展将停止。
\n\n6.10.3.4 重新扫描和进一步替换
\n在替换列表中的所有参数都已被替换并且 # 和 ## 处理已发生后,所有地标预处理标记都将被删除。然后重新扫描生成的预处理标记序列以及源文件的所有后续预处理标记,以查找更多要替换的宏名称。
\n
但附件 J.1 指出,这是否使用嵌套来完成是未指定的行为:
\n\n\n当完全扩展的宏替换列表包含类似函数的宏名称作为其最后一个预处理标记并且源文件中的下一个预处理标记是 ( 时,并且该宏的完全扩展替换以第一个宏的名称和源文件中的下一个预处理标记仍然是 (,无论是否被视为嵌套替换 (6.10.3)。
\n
好吧,公平地说,大多数预处理器都使用非嵌套方法,但是什么允许以下方法工作?
\n#define A() B(\n#define B() A(\nA()))))\nRun Code Online (Sandbox Code Playgroud)\n现在假设前者会给你一个错误,因为“未终止的参数列表调用宏\'B\'”,但是你不希望它扩展到A())),A现在被漆成蓝色,这不应该给出一个错误?
此外,您可以通过检测最后一个右括号来消除错误,表明这似乎也没有使用嵌套,这很奇怪,因为标准在哪里表明这是有效的?
\n\n …