【问题标题】:Are comments always processed before the preprocessor? [duplicate]注释总是在预处理器之前处理吗? [复制]
【发布时间】:2011-01-01 20:16:30
【问题描述】:
/*
#define FOO
*/
#ifdef FOO
#define BAR "pirate"
#else
#define BAR "ninja"
#endif
int main() { printf(BAR); getchar(); }
在此代码中未定义 FOO (Visual Studio 2008)。我假设首先处理 cmets,然后是预处理器,然后是代码。 cmets总是在预处理器之前处理吗?这是标准的一部分吗?
【问题讨论】:
标签:
c
comments
c-preprocessor
【解决方案1】:
根据 C 标准,在程序的翻译(编译)过程中有 8 个翻译阶段。每个注释在翻译阶段 3 中被替换为空白字符,而预处理指令在阶段 4 中执行。
【解决方案2】:
我假设首先处理 cmets,然后是预处理器,然后是代码。 cmets 总是在预处理器之前处理吗?
预处理器工作的一部分是删除cmets。在这种情况下,它并不关心您在 cmets 中有指令;它仍然像任何其他评论一样被删除。
【解决方案3】:
是的,预处理器在处理指令之前替换了 cmets。
来自 C99 标准的第 5.1.1.2 节(翻译阶段):
3) 源文件被分解成预处理标记和空白字符序列(包括 cmets)......每个注释被一个空格字符替换......
4) 执行预处理指令,扩展宏调用,......
【解决方案4】:
是的,从语言标准的角度来看,在预处理器开始工作之前处理 cmets(替换为空格)。
在实际实现中,cmets 的处理可以由处理预处理器指令并执行宏替换的相同代码(例如,相同的可执行文件)完成,但结果必须相同:cmets 对预处理器本身没有影响。
在旧代码和/或非标准代码中,有时可能会看到一些依赖于非标准行为的技巧,涉及特定于实现的 cmets 与预处理器关系,例如,使用预处理器指令创建 cmets
#define CONCAT(a, b) a##b
#define BEGIN_COMMENT CONCAT(/, *)
#define END_COMMENT CONCAT(*, /)
BEGIN_COMMENT
This code is supposedly commented-out
END_COMMENT
或使用 cmets 进行预处理器级连接(使用不支持宏定义中的 ## 运算符的 C 编译器)
#define OLD_CONCAT(a, b) a/**/b
这些技巧在标准 C 中都不合法。它们都没有真正起作用。
【解决方案5】:
一些快速研究表明,cmets 被预处理器转换为空格。所以,这都是同一个流程的一部分。
根据Wikipedia,cmets 在预处理器指令之前处理。