如果 MACRO 未被定义,这两个表达式是否相同?
#ifdef MACRO
Not valid C or C++ code
#endif
/*
Not valid C or C++ code
*/
在GCC 4.7.1中,它似乎是等效的,但是否有更多的预处理器呢?
#ifdef MACRO
Not valid C or C++ code
#endif
/*
Not valid C or C++ code
*/
这取决于你所说的“不是有效的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教程都警告您不要这样做),请注意保留HTML标签:
/* you can't nest /* block comments */ these words are not commented */
#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
的位置。通常这不是问题,因为在你禁用代码之前,代码已经被编译过了,所以它不应该有任何东西会导致分词错误。 /* Comments /* inside */ comments are not allowed. */
#if 0
而不是#ifdef MACRO
。#if 0
Invalid C source code
#endif
/*
根本不应该存在,无论是否被#if
排除。 - Elazar/*
,那么你也应该担心在“无效的C源代码”中间的#endif
。 - Elazar#ifdef / #endif
指令可以嵌套,但是注释不能。我不是在提到“不匹配的/*
”,因为它也无法与匹配的 /*
一起工作。 - md5是的,它们是等价的,预处理阶段会在编译器真正看到代码之前消除非有效的C或C++代码
。
预处理包括删除注释以及被#if
过滤掉的代码。
但是, 如果有人使用-DMACRO
编译代码,#ifdef
版本会让你陷入麻烦,最好使用#if 0
来通过预处理器删除代码。
C11 6.10.1 Conditional inclusion /6
:
这意味着,如果任何形式的代码(如按顺序检查每个指令的条件。如果它评估为 false(零),则跳过其所控制的组。
if
、ifdef
等)评估为 false,则不会对该组进行任何处理,并且在后续处理阶段中完全删除。它不会转换成注释。#ifdef
内部的代码不会有任何痕迹:// before
#ifdef MACRO
Not valid C or C++ code
#endif
// after
预编译后:
// before
// after
里面没有剩余的代码。
// before
和 // after
注释,因为注释会在预处理阶段之前被剥离。 - gx_#if 0
code(); /* possibly with comments. */
#endif
这使您能够禁用包含注释的大部分代码,即使它们。因此,与普通注释相比,它更适用于禁用代码的部分。
但是有一个警告。我曾经遇到过编译器无法处理类似以下代码的情况:
#ifdef __GNUC__
#nonstandardpreprocessordirective
#endif
"nonstandardpreprocessordirective" 是一个只在 GCC 上有效的预处理器指令。我不确定标准对此有何规定,但它在过去的实际应用中曾经引起问题。我不记得是哪个编译器了。
它们很接近,但还不完全相同。假设没有定义宏(或者假设您使用其他答案中推荐的#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
是用于禁用 合法 代码的。任意文本都不应该存在于源代码中。
是的,大多数预处理器(如果不是全部)都会删除注释和评估为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
MACRO未定义
,则是的,代码将无法编译,在这两种情况下,预处理器用于条件编译,如果定义为真,则代码编译,否则不编译。 - Grijesh Chauhan