C++ #ifdef vs #if - 作为启用/禁用特定代码段编译的方法,哪个更好/更安全?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/135069/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
#ifdef vs #if - which is better/safer as a method for enabling/disabling compilation of particular sections of code?
提问by Jon Cage
This may be a matter of style, but there's a bit of a divide in our dev team and I wondered if anyone else had any ideas on the matter...
这可能是风格问题,但我们的开发团队存在一些分歧,我想知道是否还有其他人对此事有任何想法......
Basically, we have some debug print statements which we turn off during normal development. Personally I prefer to do the following:
基本上,我们有一些在正常开发过程中关闭的调试打印语句。我个人更喜欢执行以下操作:
//---- SomeSourceFile.cpp ----
#define DEBUG_ENABLED (0)
...
SomeFunction()
{
int someVariable = 5;
#if(DEBUG_ENABLED)
printf("Debugging: someVariable == %d", someVariable);
#endif
}
Some of the team prefer the following though:
不过,有些团队更喜欢以下内容:
// #define DEBUG_ENABLED
...
SomeFunction()
{
int someVariable = 5;
#ifdef DEBUG_ENABLED
printf("Debugging: someVariable == %d", someVariable);
#endif
}
...which of those methods sounds better to you and why? My feeling is that the first is safer because there is always something defined and there's no danger it could destroy other defines elsewhere.
...这些方法中哪一种对您来说听起来更好,为什么?我的感觉是第一个更安全,因为总是有一些定义,并且没有可能破坏其他地方的其他定义的危险。
采纳答案by Roddy
My initial reaction was #ifdef
, of course, but I think #if
actually has some significant advantages for this - here's why:
我最初的反应#ifdef
当然是,但我认为这#if
实际上有一些显着的优势 - 这就是原因:
First, you can use DEBUG_ENABLED
in preprocessor andcompiled tests. Example - Often, I want longer timeouts when debug is enabled, so using #if
, I can write this
首先,您可以DEBUG_ENABLED
在预处理器和编译测试中使用。示例 - 通常,当启用调试时,我想要更长的超时,所以使用#if
,我可以写这个
DoSomethingSlowWithTimeout(DEBUG_ENABLED? 5000 : 1000);
... instead of ...
... 代替 ...
#ifdef DEBUG_MODE
DoSomethingSlowWithTimeout(5000);
#else
DoSomethingSlowWithTimeout(1000);
#endif
Second, you're in a better position if you want to migrate from a #define
to a global constant. #define
s are usually frowned on by most C++ programmers.
其次,如果您想从 a 迁移#define
到全局常量,您处于更好的位置。#define
大多数 C++ 程序员通常不喜欢 s。
And, Third, you say you've a divide in your team. My guess is this means different members have already adopted different approaches, and you need to standardise. Ruling that #if
is the preferred choice means that code using #ifdef
will compile -and run- even when DEBUG_ENABLED
is false. And it's mucheasier to track down and remove debug output that is produced when it shouldn't be than vice-versa.
第三,你说你的团队存在分歧。我的猜测是这意味着不同的成员已经采用了不同的方法,您需要标准化。裁定#if
是优选的选择单元,其使用代码#ifdef
将编译-and时甚至RUN-DEBUG_ENABLED
是假的。而且它的很多容易追查并卸下时,它不应该比反之亦然生产调试输出。
Oh, and a minor readability point. You should be able to use true/false rather than 0/1 in your #define
, and because the value is a single lexical token, it's the one time you don't need parentheses around it.
哦,还有一个小的可读性点。您应该能够在您的 中使用 true/false 而不是 0/1 #define
,并且因为该值是单个词法标记,所以这是您不需要括号的一次。
#define DEBUG_ENABLED true
instead of
代替
#define DEBUG_ENABLED (1)
回答by R.. GitHub STOP HELPING ICE
They're both hideous. Instead, do this:
他们俩都很可怕。相反,请执行以下操作:
#ifdef DEBUG
#define D(x) do { x } while(0)
#else
#define D(x) do { } while(0)
#endif
Then whenever you need debug code, put it inside D();
. And your program isn't polluted with hideous mazes of #ifdef
.
然后每当你需要调试代码时,把它放在D();
. 而且您的程序不会被#ifdef
.
回答by Terence Simpson
#ifdef
just checks if a token is defined, given
#ifdef
只检查是否定义了令牌,给定
#define FOO 0
then
然后
#ifdef FOO // is true
#if FOO // is false, because it evaluates to "#if 0"
回答by Brent Priddy
We have had this same problem across multiple files and there is always the problem with people forgetting to include a "features flag" file (With a codebase of > 41,000 files it is easy to do).
我们在多个文件中遇到了同样的问题,并且总是存在人们忘记包含“功能标志”文件的问题(使用 > 41,000 个文件的代码库很容易做到)。
If you had feature.h:
如果你有 feature.h:
#ifndef FEATURE_H
#define FEATURE_H
// turn on cool new feature
#define COOL_FEATURE 1
#endif // FEATURE_H
But then You forgot to include the header file in file.cpp:
但是后来你忘了在 file.cpp 中包含头文件:
#if COOL_FEATURE
// definitely awesome stuff here...
#endif
Then you have a problem, the compiler interprets COOL_FEATURE being undefined as a "false" in this case and fails to include the code. Yes gcc does support a flag that causes a error for undefined macros... but most 3rd party code either defines or does not define features so this would not be that portable.
那么你有一个问题,在这种情况下,编译器将未定义的 COOL_FEATURE 解释为“false”并且无法包含代码。是的 gcc 确实支持导致未定义宏错误的标志......但大多数 3rd 方代码要么定义要么不定义功能,所以这不会那么便携。
We have adopted a portable way of correcting for this case as well as testing for a feature's state: function macros.
我们采用了一种可移植的方式来纠正这种情况以及测试功能的状态:函数宏。
if you changed the above feature.h to:
如果您将上述 feature.h 更改为:
#ifndef FEATURE_H
#define FEATURE_H
// turn on cool new feature
#define COOL_FEATURE() 1
#endif // FEATURE_H
But then you again forgot to include the header file in file.cpp:
但是你又忘记在 file.cpp 中包含头文件:
#if COOL_FEATURE()
// definitely awseome stuff here...
#endif
The preprocessor would have errored out because of the use of an undefined function macro.
由于使用了未定义的函数宏,预处理器会出错。
回答by Mike Thompson
For the purposes of performing conditional compilation, #if and #ifdef are almostthe same, but not quite. If your conditional compilation depends on two symbols then #ifdef will not work as well. For example, suppose you have two conditional compilation symbols, PRO_VERSION and TRIAL_VERSION, you might have something like this:
为了执行条件编译,#if 和#ifdef几乎相同,但不完全相同。如果您的条件编译依赖于两个符号,那么 #ifdef 将无法正常工作。例如,假设你有两个条件编译符号,PRO_VERSION 和 TRIAL_VERSION,你可能有这样的东西:
#if defined(PRO_VERSION) && !defined(TRIAL_VERSION)
...
#else
...
#endif
Using #ifdef the above becomes much more complicated, especially getting the #else part to work.
使用#ifdef 上面变得更加复杂,尤其是让#else 部分工作。
I work on code that uses conditional compilation extensively and we have a mixture of #if & #ifdef. We tend to use #ifdef/#ifndef for the simple case and #if whenever two or more symbols are being evaluation.
我处理广泛使用条件编译的代码,我们混合使用了#if 和#ifdef。我们倾向于在简单的情况下使用#ifdef/#ifndef,在计算两个或多个符号时使用#if。
回答by Derek Park
I think it's entirely a question of style. Neither really has an obvious advantage over the other.
我认为这完全是一个风格问题。两者都没有比另一个明显的优势。
Consistency is more important than either particular choice, so I'd recommend that you get together with your team and pick one style, and stick to it.
一致性比任何一种特定选择都更重要,因此我建议您与您的团队一起选择一种风格,并坚持下去。
回答by Jim Buck
I myself prefer:
我个人更喜欢:
#if defined(DEBUG_ENABLED)
Since it makes it easier to create code that looks for the opposite condition much easier to spot:
因为它可以更轻松地创建寻找相反条件的代码,更容易发现:
#if !defined(DEBUG_ENABLED)
vs.
对比
#ifndef(DEBUG_ENABLED)
回答by Lev
It's a matter of style. But I recommend a more concise way of doing this:
这是一个风格问题。但我推荐一种更简洁的方法来做到这一点:
#ifdef USE_DEBUG
#define debug_print printf
#else
#define debug_print
#endif
debug_print("i=%d\n", i);
You do this once, then always use debug_print() to either print or do nothing. (Yes, this will compile in both cases.) This way, your code won't be garbled with preprocessor directives.
您执行一次,然后始终使用 debug_print() 打印或不执行任何操作。(是的,这将在两种情况下编译。)这样,您的代码就不会因预处理器指令而出现乱码。
If you get the warning "expression has no effect" and want to get rid of it, here's an alternative:
如果您收到警告“表达式无效”并想摆脱它,这里有一个替代方案:
void dummy(const char*, ...)
{}
#ifdef USE_DEBUG
#define debug_print printf
#else
#define debug_print dummy
#endif
debug_print("i=%d\n", i);
回答by Martin Beckett
#if
gives you the option of setting it to 0 to turn off the functionality, while still detecting that the switch is there.
Personally I always #define DEBUG 1
so I can catch it with either an #if or #ifdef
#if
为您提供将其设置为 0 以关闭功能的选项,同时仍然检测到开关在那里。
就个人而言,我总是#define DEBUG 1
这样我就可以用 #if 或 #ifdef 来捕捉它
回答by paercebal
#if and #define MY_MACRO (0)
#if 和 #define MY_MACRO (0)
Using #if means that you created a "define" macro, i.e., something that will be searched in the code to be replaced by "(0)". This is the "macro hell" I hate to see in C++, because it pollutes the code with potential code modifications.
使用#if 意味着您创建了一个“define”宏,即,将在代码中搜索以替换为“(0)”的内容。这是我讨厌在 C++ 中看到的“宏地狱”,因为它会通过潜在的代码修改污染代码。
For example:
例如:
#define MY_MACRO (0)
int doSomething(int p_iValue)
{
return p_iValue + 1 ;
}
int main(int argc, char **argv)
{
int MY_MACRO = 25 ;
doSomething(MY_MACRO) ;
return 0;
}
gives the following error on g++:
在 g++ 上给出以下错误:
main.cpp|408|error: lvalue required as left operand of assignment|
||=== Build finished: 1 errors, 0 warnings ===|
Only oneerror.
只有一处错误。
Which means that your macro successfully interacted with your C++ code: The call to the function was successful. In this simple case, it is amusing. But my own experience with macros playing silently with my code is not full of joy and fullfilment, so...
这意味着您的宏成功与您的 C++ 代码交互:对函数的调用成功。在这个简单的案例中,它很有趣。但是我自己使用宏默默地使用我的代码的经验并不充满喜悦和满足,所以......
#ifdef and #define MY_MACRO
#ifdef 和 #define MY_MACRO
Using #ifdef means you "define" something. Not that you give it a value. It is still polluting, but at least, it will be "replaced by nothing", and not seen by C++ code as lagitimate code statement. The same code above, with a simple define, it:
使用 #ifdef 意味着你“定义”了一些东西。不是你给它一个价值。它仍然在污染,但至少,它将被“无所取代”,并且不会被 C++ 代码视为最后的代码语句。上面相同的代码,通过一个简单的定义,它:
#define MY_MACRO
int doSomething(int p_iValue)
{
return p_iValue + 1 ;
}
int main(int argc, char **argv)
{
int MY_MACRO = 25 ;
doSomething(MY_MACRO) ;
return 0;
}
Gives the following warnings:
给出以下警告:
main.cpp||In function ‘int main(int, char**)':|
main.cpp|406|error: expected unqualified-id before ‘=' token|
main.cpp|399|error: too few arguments to function ‘int doSomething(int)'|
main.cpp|407|error: at this point in file|
||=== Build finished: 3 errors, 0 warnings ===|
So...
所以...
Conclusion
结论
I'd rather live without macros in my code, but for multiple reasons (defining header guards, or debug macros), I can't.
我宁愿在我的代码中没有宏,但出于多种原因(定义标题保护或调试宏),我不能。
But at least, I like to make them the least interactive possible with my legitimate C++ code. Which means using #define without value, using #ifdef and #ifndef (or even #if defined as suggested by Jim Buck), and most of all, giving them names so long and so alien no one in his/her right mind will use it "by chance", and that in no way it will affect legitimate C++ code.
但至少,我喜欢让它们与我的合法 C++ 代码交互尽可能少。这意味着使用没有价值的#define,使用#ifdef 和#ifndef(甚至是Jim Buck 建议的#if 定义),最重要的是,给它们命名如此之长,如此陌生,他/她的正常头脑中的任何人都不会使用它是“偶然的”,而且绝不会影响合法的 C++ 代码。
Post Scriptum
后脚本
Now, as I'm re-reading my post, I wonder if I should not try to find some value that won't ever ever be correct C++ to add to my define. Something like
现在,当我重新阅读我的帖子时,我想知道我是否应该尝试找到一些永远不会正确的 C++ 值来添加到我的定义中。就像是
#define MY_MACRO @@@@@@@@@@@@@@@@@@
that could be used with #ifdef and #ifndef, but not let code compile if used inside a function... I tried this successfully on g++, and it gave the error:
可以与#ifdef 和#ifndef 一起使用,但如果在函数内部使用,则不允许代码编译......我在g ++上成功尝试了这个,它给出了错误:
main.cpp|410|error: stray ‘@' in program|
Interesting. :-)
有趣的。:-)