什么时候进行条件编译是一个好主意,何时是一个非常糟糕的主意?
通过条件编译,我的意思是使用#ifdef
来仅在某些条件下编译某些代码。 #defined
本身可以位于公共头文件中,也可以通过-D
编译器指令引入。
答案 0 :(得分:7)
好主意:
extern "C" {
和}
,以便C ++实现和API的C客户端可以使用相同的标头糟糕的主意:
答案 1 :(得分:2)
基本上,您应该尝试将有条件编译的代码量保持在最低限度,因为您应该尝试测试所有这些并且有很多条件会使这更加困难。它还降低了代码的可读性;有条件地编译整个文件更清楚,例如,通过将平台特定的代码放在每个平台的单独文件中,并且从问题的其余部分的角度来看,所有这些都具有相同的API。还要尽量避免在函数头中使用它;再次,那是因为那是一个特别令人困惑的地方。
但这并不是说你永远不应该使用条件编译。试着保持简短和最小化。 (我可以,我使用条件编译来控制其他宏的定义,然后在其余的代码中使用它们;至少对我来说似乎更清楚。)
答案 2 :(得分:2)
不要在代码中加入ifdef 这使得阅读和理解变得非常困难。请使代码尽可能易于阅读维护者(他知道你住在哪里并拥有一个Ax)。
将条件代码隐藏在单独的函数中,并使用ifdef定义正在使用的函数。
不要使用else部分进行定义。如果您认为一个平台是独一无二的,而其他所有平台都是相同的。这是不太可能的,更有可能的是你知道在几个平台上会发生什么,但是你应该使用#else部分来粘贴#error,这样当它被移植到新平台时,开发人员必须明确地修复条件。他的平台。
#if defined(WINDOWS)
#define MyPlatfromSleepSeconds(x) sleep(x * 1000)
#elif defined (UNIX)
#define MyPlatfromSleepSeconds(x) Sleep(x)
#else
#error "Please define appropriate sleep for your platform"
#endif
不要试图将宏扩展为多行代码。这导致了疯狂。
#if defined(SOLARIS_3_1_1)
#define DO_SOME_TASK(x,y) doPartA(x); \
doPartB(y); \
couple(x,y)
#elif defined(WINDOWS)
#define DO_SOME_TASK(x,y) doAndCouple(x,y)
#else
#error "Please define appropriate DO_SOME_TASK for your platform"
#endif
如果您在Windows上开发代码,那么稍后在solaris 3_1_1上进行测试时,当人们执行以下操作时,您可能会发现意外错误:
int loop;
for(loop = 0;loop < 10;++loop)
DO_SOME_TASK(loop,loop); // Windows works fine()
// Solaras. Only doPartA() is in the loop.
// The other statements are done when the loop finishes
答案 3 :(得分:1)
每当你不知道自己在做什么时,这是一个坏主意。当你以这种方式有效地解决问题时,这可能是一个好主意:)。
您描述条件编译的方式,包括警卫是其中的一部分。使用它不仅是个好主意。这是一种避免编译错误的方法。
对我来说,条件编译也是一种针对多个编译器和操作系统的方法。我参与了一个可以在Windows XP和更新版本,32或64位上编译的lib,使用MinGW和Visual C ++,在Linux 32和64位上使用gcc / g ++,在MacOS上使用我不知道-what(我不是在维护它,但我认为它是一个gcc端口)。如果没有预处理器条件,创建一个可在任何地方编译的单个源文件几乎是不可能的。
答案 4 :(得分:1)
条件编译的另一个实际用途是“注释掉”包含标准“C”注释的代码段(即/ * * /)。有些编译器不允许嵌套这些注释,例如:
/* comment out block of code
.... code ....
/* This is a standard
* comment.
*/ ... oopos! Some compilers try to compile code after this closing comment.
.... code ....
end of block of code*/
(正如您在语法高亮显示中所看到的,StackOverflow不会嵌套注释。)
相反,您可以使用#ifdef
来获得正确的效果,例如:
#ifdef _NOT_DEFINED_
.... code ....
/* This is a standard
* comment.
*/
.... code ....
#endif
答案 5 :(得分:0)
过去如果你想生成真正可移植的代码,你必须采用某种形式的条件编译。随着便携式库(例如APR,增强等)的激增,这个原因很少有恕我直言。如果您使用条件编译只是编译出特定构建不需要的代码块,您应该重新审视您的设计 - 我应该想象这将成为维护的噩梦。
说了这么多,如果你确实需要使用条件编译,我会尽可能地隐藏代码的主体,并限制到非常容易理解的特定情况。
答案 6 :(得分:0)
良好/合理的用途是基于成本/效益分析。显然,这里的人非常清楚风险:
但是,有些用途通常属于净效益类别:
main()
而不为库添加答案 7 :(得分:-4)
总是一个坏主意。它的作用是有效地创建源代码的多个版本,所有这些都需要进行测试,这至少可以说是一种痛苦。不幸的是,像许多坏事一样,它有时是不可避免的。在编写需要在Windows和Linux之间移植的代码时,我会以非常小的数量使用它,但如果我发现自己做了很多,我会考虑替代方案,例如有两个独立的开发子树。