c - #ifdef MACRO 是否等同于注释

标签 c comments c-preprocessor conditional-compilation

假设没有定义MACRO,这些是否等价

#ifdef MACRO
    Not valid C or C++ code
#endif

/*
    Not valid C or C++ code
*/

在 GCC 4.7.1 中,这似乎是等效的,但是否有预处理器做得更多?

最佳答案

这取决于您所说的“无效的 C 或 C++ 代码”是什么意思。

评论 中的文本不必符合大多数语言规则。它甚至没有被标记化。这是完全有效的:

/* This comment doesn't contain a valid sequence of preprocessing tokens
   (because of the apostrophe).  */

它必须遵守的唯一规则是控制注释结束位置的规则。人们经常在行注释中被反斜杠换行符绊倒(事实上,SO 的语法高亮器曾经犯过这个错误!)

// Line comment with ascii art ending with a \
   Oops! This line is commented out too!

并且更少地(如果只是因为每个 C 教程都会警告您这一点)通过 block 注释而不是嵌套:

/* you can't nest /* block comments */ these words are not commented */

另一方面,“跳过”预处理器条件“组”中的文本确实必须符合某些语言规则。标准(C99 §6.10.1p5)的确切词是

Each directive’s condition is checked in order. If it evaluates to false (zero), the group that it controls is skipped: directives are processed only through the name that determines the directive in order to keep track of the level of nested conditionals; the rest of the directives’ preprocessing tokens are ignored, as are the other preprocessing tokens in the group.

有两个重要的位。首先,文本标记化的,因此它确实必须是预处理标记的有效序列。

#if 0
This skipped conditional group doesn't contain a valid sequence of
preprocessing tokens (because of the apostrophe).
#endif

是语法错误。

$ gcc -fsyntax-only test.c
test.c:2:37: warning: missing terminating ' character
 this skipped conditional group doesn't contain a valid sequence of
                                     ^

其次,指令仍然被部分处理“以跟踪嵌套条件的级别”,这意味着您可以这样做:

#if 0 // forget this entire mess
    #ifdef __linux__
    do_linux_specific_thing();
    #elif defined __APPLE__
    do_osx_specific_thing();
    #elif defined _WIN32
    do_windows_specific_thing();
    #endif
#endif

而且你不能这个:

    #ifdef __linux__
    do_linux_specific_thing();
    #elif defined __APPLE__
    do_osx_specific_thing();
#if 0 // forget windows
    #elif defined _WIN32
    do_windows_specific_thing();
    #endif
#endif

(你不会得到最后一个错误,但是......

$ gcc -E -P -U__linux__ -D__APPLE__ -D_WIN32 test.c
    do_osx_specific_thing();
    do_windows_specific_thing();

……我不认为这是写它的人的本意。)


该语言的许多指南告诉您使用 #if 0 来“注释掉”您想暂时禁用的大块代码区域。他们这样说是因为 block 注释不会嵌套。如果您尝试禁用带有 block 注释的代码区域,但该区域中有 block 注释,则注释掉将过早结束并且代码可能无法编译。这在 C 没有行注释的时代更为重要;一些项目仅使用行注释进行注释,为禁用代码保留 block 注释。

但是因为 #if 0#endif 中的代码仍然是标记化的,并且嵌套的预处理器条件必须仍然平衡,所以你必须要小心你在哪里放入#if 0#endif。这通常不是问题,因为在您禁用它之前用于编译的代码,所以它不应该包含任何导致标记化错误的内容。

关于c - #ifdef MACRO 是否等同于注释,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17104594/

相关文章:

c++ - 传递 malloc 指针给我错误

visual-studio - Visual Studio 的评论重播

php - 打开/关闭打印调试消息的功能

java - 使用 StreamTokenizer 过滤 Java 评论

c++ - 有没有办法将 #define 指令设为 'expand'?

c - '=' token 之前的预期符号

C函数签名问题

c++ - C++ 编译器是否优化掉未使用的#includes?

c++ - 跳过所有 Googletest 单元测试类的编译

c++ - 两个数字的按位连接