C++ 为什么人们使用#ifdef进行特性标志测试?

C++ 为什么人们使用#ifdef进行特性标志测试?,c++,c,c-preprocessor,conditional-compilation,C++,C,C Preprocessor,Conditional Compilation,人们。A证明其使用是普遍的 但是#ifdef NAME(或者相当于#if defined(NAME)和相关的#ifndef NAME(和#if!defined(NAME))有一个严重的缺陷: 标题.h source.cpp gcc-DIS_SPECIAL source.cpp 很明显,它会过去的 source1.cpp 但是,我们也会这样做 source0.cpp P>这是一个错误的做法,一些C++编译器通过了一个在强> c>强>模式(由于扩展或命令行选项)处理的文件,有效地执行了 >定义了.

人们。A证明其使用是普遍的

但是
#ifdef NAME
(或者相当于
#if defined(NAME)
和相关的
#ifndef NAME
(和
#if!defined(NAME)
)有一个严重的缺陷:

标题.h source.cpp gcc-DIS_SPECIAL source.cpp

很明显,它会过去的

source1.cpp 但是,我们也会这样做

source0.cpp <> P>这是一个错误的做法,一些C++编译器通过了一个在<>强> c>强>模式(由于扩展或命令行选项)处理的文件,有效地执行了<代码> >定义了.pCPLUS PLUS 0 。
#ifdef __cplusplus
extern "C" {
#endif
/* ... */
#ifdef __cplusplus
}
#endif
C模式下处理,其中
extern“C”
是无效语法,因为
\uuucplusplus
实际上自动定义为
0

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

#if __cplusplus
extern "C" {
#endif
/* ... */
#if __cplusplus
}
#endif
为什么人们在这种情况下仍然使用
#ifdef
?他们只是不知道
#if
在未定义的名称上工作得非常好吗?或者对于条件编译
#if
#ifdef
相比,是否存在实际的缺点?


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

#ifndef MAX_FILES
#define MAX_FILES 64
#endif
我只是在讨论旗帜测试的情况

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

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

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

他们只是不知道#if在未定义的名称上工作得非常好吗

我不知道。这是什么语义?一个未定义的名称是否假定为0?我想向一个刚开始几乎不了解预处理器的人解释一下吗

或者,对于条件编译,“if vs”ifdef是否存在实际的缺点

对我来说,名称存在的
#ifdef/#ifndef
的二进制性质是一个清晰的好处。
另外,我对这两种结构的主要用法都是用于include-guards。使用
#ifndef

时,这种模式是最干净的。我无法解释为什么一般人更喜欢
#ifdef
而不是
#if
,但我至少可以说出我为什么这样做。基于刚才的内省(因为你问过——我以前从未明确考虑过),原因有二:


1) 我希望我的宏(我尽量少用)具有尽可能简单的语义,并相应地尽可能“无类型”。我假设宏(如果它们有任何类型的话)要么是“类型无关的函数”(注意:这里我非常喜欢模板,但有时什么都有……),要么基本上只是布尔标志。因此,对我来说,即使将
1
的值指定给宏,也会使它变得不稳定。(例如,如果您有
#define"cplusplus 2
,这意味着什么?这是否与
1

2) 关于它们是“标志”的最后一点,与我在命令行(或IDE)中指定为条件编译标志的内容中主要使用这些标志的事实相一致。事实上,在我的软件团队中,当我们编写C++时,我们基本上禁止使用宏来做其他事情。即使在条件编译的情况下,如果我们可以用其他方法(比如通过模块化)解决问题,我们也会尽量避免它们


这两个原因都与相同的基本假设有关,即尽可能避免使用宏(在C++中),因此不需要复杂的类型或不透明的语义。如果你不做这样的假设(我知道,在用C语言编程时,这是不常见的),那么事情就会发生变化,我想你关于
#的观点可能会更具影响力。

为什么这“是一件非常错误的事情”?条件询问是否定义了某个对象,并且在这两种情况下都定义了该对象。有人会期待同样的结果,不是吗?@JoshuaTaylor:这意味着编译器正确地实现了测试。这并不意味着用户选择了正确的测试。请参阅
\uuu cplusplus==0
的讨论,了解为什么这是错误的测试。或者你认为将设置从
1
更改为
0
不应该关闭它吗?我很好奇,你认为是什么让这个问题没有得到充分的研究?是因为我没有引用标准中有关
#if
和未定义宏的部分吗?因为你认为答案没有实际价值?因为这个问题写得不好,不能被普通的C和C++程序员理解吗?如果你给我反馈的话,我很乐意尝试改进。我不是投反对票的人,但我一直想改进,直到最后。这个问题从标题中对喜欢
#ifdef
的人的一个轻微侮辱开始,直到接近结尾,人们甚至都不清楚“更好”的选择是什么。有一段时间,我认为您希望人们使用
#ifndef
。n1570 C标准草案第6.10.8节(预定义的宏名称),第3条规定“实现不应预定义宏
\uu cplusplus
,也不应在任何标准头中定义它。”C模式下定义它的编译器被破坏,因此,这个特定的例子并不是
#if
超过
#ifndef
的有力论据。
-DOPTION
-DOPTION=1
之间没有区别(对于我使用过的任何预处理器)。两个都定义了一个宏<代码>选项>代码>值>代码> 1 /代码>。对于C++,16.1p4定义了<代码> >的语义,如果< /代码>在一个未定义的名称上,如下:“由于宏扩展和定义的
一元运算符执行了所有替换后,所有剩余的标识符和关键字(true和false除外)都将替换为
#define IS_SPECIAL 0
#include "header.h"
#ifdef __cplusplus
extern "C" {
#endif
/* ... */
#ifdef __cplusplus
}
#endif
#if __cplusplus
extern "C" {
#endif
/* ... */
#if __cplusplus
}
#endif
#ifndef MAX_FILES
#define MAX_FILES 64
#endif