假设没有定义MACRO,这些是等价的
#ifdef MACRO
Not valid C or C++ code
#endif
/*
Not valid C or C++ code
*/
在GCC 4.7.1中,它似乎是等效的,但是有更多的预处理器吗?
答案 0 :(得分:6)
在一般情况下,两者都是等价的。
但是,如果您的“无效的C或C ++代码”包含注释,则第一个表单将起作用,而第二个表单不起作用。这是因为C标准禁止使用叠加的评论。
/* Comments /* inside */ comments are not allowed. */
BTW,#if 0
在这种情况下通常优先于#ifdef MACRO
。
#if 0
Invalid C source code
#endif
请参阅this question。
答案 1 :(得分:6)
这取决于“无效的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教程都警告你这一点)通过块注释而不是嵌套(语法高亮显示得到这个):
/* you can't nest /* block comments */ these words are not commented */
另一方面,“跳过的”预处理器条件“组”中的文本必须符合该语言的某些规则。标准的确切词语(C99§6.10.1p5)是
按顺序检查每个指令的条件。如果它的计算结果为false(零),则为该组 跳过它控制的指令:仅通过确定的名称处理指令 该指令是为了跟踪嵌套条件的级别;剩下的 指令的预处理标记被忽略,其他预处理标记也被忽略 基。
有两个重要的部分。首先,文本是标记化的,因此 必须是预处理标记的有效序列。
#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
“注释掉”要暂时禁用的大型代码区域。他们这样说是因为块注释没有嵌套。如果您尝试使用块注释禁用代码区域,但该区域内存在块注释,则注释将过早结束,并且可能代码将无法编译。在C没有行评论的日子里,这一点更为重要;一些项目仅使用行注释进行注释,为禁用代码保留块注释。
但是因为#if 0
... #endif
中的代码仍然被标记化,并且嵌套的预处理器条件必须仍然平衡,所以你必须要小心谨慎放置#if 0
和#endif
。这通常不是问题,因为在您禁用它之前用于编译的代码,因此它不应该有任何内容导致标记化错误。
答案 2 :(得分:5)
是的,它们是等价的,预处理阶段将在编译器正确看到代码之前消除Not valid C or C++ code
。
预处理涉及删除评论以及#if
编译的代码。
但如果有人使用-DMACRO
编译代码,则#ifdef
版本会让您遇到麻烦,最好使用#if 0
通过预处理器删除代码。
答案 3 :(得分:1)
标准的相关部分是C11 6.10.1 Conditional inclusion /6
:
按顺序检查每个指令的条件。如果它的计算结果为false(零),则为该组 它控制的内容被跳过。
这意味着,如果各种表单中的任何一种(if
,ifdef
等)评估为false,则 no 处理该组已完成且完全是在后续处理阶段被删除。 不会变成评论。
答案 4 :(得分:0)
不,在您的最终代码中,#ifdef
内不会有任何代码痕迹:
// before
#ifdef MACRO
Not valid C or C++ code
#endif
// after
预先编译后:
// before
// after
其中有 no 剩余代码。
答案 5 :(得分:0)
如果未定义MACRO,则它们应该是等效的。注释掉大块代码的典型方法通常是:
#if 0
code(); /* possibly with comments. */
#endif
这允许您禁用大部分代码,即使它们包含注释。因此,禁用部分代码比正常注释更好。
但有一点需要注意。我遇到了一个像这样的东西窒息的编译器:
#ifdef __GNUC__
#nonstandardpreprocessordirective
#endif
其中“nonstandardpreprocessordirective”是仅适用于GCC的预处理程序指令。我不完全确定标准对此有何看法,但它在过去已经引起了现实问题。我不记得哪个编译器。
答案 6 :(得分:0)
他们很接近,但并不完全。假设未定义MACRO(或假设您正在使用其他答案中建议的#if 0
):
#ifdef MACRO
Not valid C or C++ code
*/ - does no harm
#endif - oops
more invalid code
#endif
和评论:
/*
Not valid C or C++ code
#endif - does no harm
*/ - oops
*/
评论用于评论,#ifdef
用于停用 legal 代码。任意文本都不应该存在于源文件中。
答案 7 :(得分:0)
是的,大多数预处理器(如果不是全部)将删除评估为0的注释和指令。两者之间的差异主要是功能性的。
我的建议是使用指令"评论"代码(#if 0 {} #endif)并仅使用注释进行评论(非常逻辑对吗?)。主要原因是:
#if 0 ... #if 1 #endif ... #endif
//Classic verbose code line comment #if 0 //Directive verbose line or block comment #endif #define verbose 0 #if verbose //Convenient eval directive to turn on/off this and other verbose blocks #endif