为什么人们使用#ifdef进行功能标记测试?

时间:2014-01-22 01:58:31

标签: c++ c c-preprocessor conditional-compilation

recommend #ifdef for conditional compilation by a wide marginsearch for #ifdef证实其使用是普遍的。

然而#ifdef NAME(或等效#if defined(NAME)及相关#ifndef NAME(和#if !defined(NAME))存在严重缺陷:

header.h

#ifndef IS_SPECIAL
#error You're not special enough
#endif

source.cpp

#include "header.h"
  

gcc -DIS_SPECIAL source.cpp

显然,

会通过

source1.cpp

#define IS_SPECIAL 1
#include "header.h"

但是,

也是如此

source0.cpp

#define IS_SPECIAL 0
#include "header.h"

这是完全错误的事情。一些C ++编译器传递了以 C 模式处理的文件(由于扩展或命令行选项),有效地执行#define __cplusplus 0

时我看到事情破裂了
#ifdef __cplusplus
extern "C" {
#endif
/* ... */
#ifdef __cplusplus
}
#endif

C 模式下处理,extern "C"语法无效,因为__cplusplus实际上已自动定义为0

另一方面,这对所有编译器都是正确的:

#if __cplusplus
extern "C" {
#endif
/* ... */
#if __cplusplus
}
#endif

为什么人们在这种情况下仍然使用#ifdef?他们根本不知道#if对未定义的名字完全正常吗?或条件编译#if#ifdef是否存在实际不利之处?


显然,#ifdef确实具有有效用途,例如为可配置参数提供默认值:

#ifndef MAX_FILES
#define MAX_FILES 64
#endif

我只讨论旗帜测试的情况。

2 个答案:

答案 0 :(得分:3)

  

为什么人们在这种情况下仍然使用#ifdef?

个人意见:从命令行控制起来稍微容易一些。我更喜欢-DOPTION而不是-DOPTION=1

此外,名称的存在显然是二进制的。我不必处理{0,非零,未定义}。

  

他们根本没有意识到#if在未定义的名称上运行得很好吗?

我不知道。这有什么语义?假定未定义的名称是0吗?我是否想要向那些几乎不了解预处理器的人解释一下?

  

对于条件编译,#if vs #ifdef是否存在实际缺点?

对我来说,名称存在的#ifdef/#ifndef的二元性质是明确的好处。 另外,我对这两种构造的主要用法是包含警戒。使用#ifndef时,该模式最为清晰。

答案 1 :(得分:2)

我不能说为什么一般人更喜欢#ifdef而不是#if,但我至少可以说我为什么这样做。基于刚才的内省(自从你问过 - 我以前从未明确考虑过它),有两个原因:

1)我更喜欢我的宏(我试图谨慎使用)尽可能地使用最直接的语义,并相应地作为"类型免费"尽可能。我假设宏,如果它们有任何类型,则是"类型自由函数" (注意:这里我更喜欢模板,但有时候一切......)或者基本上只是 boolean 标志。因此,即使为宏指定值1,也会为我拉伸它。 (例如,如果你有#define _cplusplus 2,它应该是什么意思?它应该以什么方式与1不同?)

2)关于他们的最后一点是" flags"我主要将这些用于我在命令行(或IDE)中指定的内容作为条件编译标志。实际上,在我的软件团队中,当我们编写C ++时,我们基本上已经禁止了#34;从使用宏到其他任何东西。即使在条件编译的情况下,如果我们可以通过其他方式解决问题(例如通过模块化),我们也会尽量避免使用它们。

这两个原因都与相同的基本假设有关,即尽可能避免使用宏(在C ++中),因此不需要类型的复杂性或不透明的语义。如果你没有做出这个假设(并且在用C语言编程时它不常见,我知道),那么这会改变一些事情,我想你对#if的观点可能会有更多的影响。 / p>