#if defined MACRO和#ifdef MACRO等价吗?

29

我有一些代码,希望能够拥有两种模式:debugverbose。我在头文件中这样定义它们:

#define verbose TRUE
#define debug TRUE

到目前为止,我的代码只使用了

#if(debug)
  //code
#endif

但是使用它更加合适吗?

#ifdef debug
  // code
#endif

我之前看到了一些有关预处理宏的东西,但当时并没有懂。所以,我有一个问题: #if defined MACRO#ifdef MACRO 等价吗?哪一个更适合用于启用/禁用特定代码段?


10
似乎这段文字是将#ifdefif进行比较,而不是如标题所示的与#if defined进行比较。 - Oliver Charlesworth
6
两者的区别在于#ifdef只能使用单个条件, 而#if defined(NAME) 可以使用复合条件。 - LPs
3
顺便说一下,编辑后你的代码有所不同:#if调试检查debug是否为真,而#ifdef仅检查debug是否被定义。 - LPs
不清楚的问题:请确定您是在将#ifdef与标题中的#if defined进行比较;还是像您的代码示例中一样,将#if debug#ifdef debug进行比较。 - M.M
@M.M 我进行了一次更正。 - msc
显示剩余2条评论
5个回答

36
#ifdef MACRO
#if defined (MACRO)

将会完全执行相同的操作。然而,定义的(宏)只是在#if内评估为0或1的表达式,可以与其他表达式组合使用。例如

#if defined (MACRO) && ! defined (MACRO2)
    // Do this
#else
    // Do that
#endif
尝试使用#ifdef做到这一点 - 除非您的代码变得非常笨拙,否则无法做到。

8
defined 不需要括号。它有两种形式:defined (identifier)defined identifier - Kaz

9

#if defined(MACRO)#ifdef MACRO相同,但更长。另一方面,它允许使用||&&添加额外的条件。

#if MACRO#ifdef MACRO类似,但不完全相同。如果MACRO0,那么#if MACRO将是负数——它要求定义MACRO并且不为0#ifdef仅检查是否已定义,即使没有值(#define MACRO)。

现在使用#if和值为1或0启用/禁用定义较为流行:

#define FLAG_X      1 // 或 0


9
不,它们完全不等同。如果MACRO计算为非零,则编译#if MACRO分支。另一方面,如果MACRO被定义了,无论它的值是什么,#ifdef MACRO分支都会被编译。
#include <stdio.h>

#define VAR_SET_TO_TRUE 1
#define VAR_SET_TO_FALSE 0

int main()
{

#if VAR_SET_TO_TRUE
    printf("#if VAR_SET_TO_TRUE\n");
#endif

#if VAR_SET_TO_FALSE
    printf("#if VAR_SET_TO_FALSE\n");
#endif

#if VAR_UNSET
    printf("#if VAR_UNSET\n");
#endif



#ifdef VAR_SET_TO_TRUE
    printf("#ifdef VAR_SET_TO_TRUE\n");
#endif

#ifdef VAR_SET_TO_FALSE
    printf("#ifdef VAR_SET_TO_FALSE\n");
#endif

#ifdef VAR_UNSET
    printf("#ifdef VAR_UNSET\n");
#endif

}

将输出

#if VAR_SET_TO_TRUE
#ifdef VAR_SET_TO_TRUE
#ifdef VAR_SET_TO_FALSE

请注意,代码行printf("#ifdef VAR_SET_TO_FALSE\n");被编译,而代码行printf("#if VAR_SET_TO_FALSE\n");没有被编译。第一行被编译,因为VAR_SET_TO_FALSE已经定义,即使它的值是false

1
OP询问的是#ifdef#if defined之间的区别,而不是#if#if defined之间的区别 - 也许您可以根据这种情况调整您的答案。另外从记忆中得知,如果RHS计算结果为非零而不是1,则执行#if子句。 - abligh

3
如果我正确理解了你的问题,标题有误导性,应该是:
Is #if MACRO equivalent to #ifdef MACRO?

它们并不等同,但它们可以(而且经常)都用于指定二进制模式,这些模式要么是开启的,要么是关闭的。选择哪种方式,我认为是个人喜好的问题。
你正在使用第一种选项,可能有以下原因:
#define verbose true

或者

#define verbose false

然后使用以下任一方式检查模式:

#if verbose

或者

#if !verbose

实际上,我建议您使用TRUE或1代替true,使用FALSE或0代替false,因为true和false是C/C++值(或可以是),而预处理程序无法访问C/C++值。

无论如何,指定二进制模式的另一种常见方法是定义标志或将其保留未定义,这样您可以有以下任一选项:

#define verbose any thing (including nothing) goes here

或者省略#define。
然后您可以通过以下方式测试标志是否已定义:
#ifdef verbose

或其等效物
#if defined(verbose)

注:在这种情况下,您不需要测试标志的值,而只需测试它是否已定义。

如果更方便的话,您也可以使用以下方法来测试标志是否未定义:

#ifndef verbose

或其等同物

#if !defined(verbose)

[给楼主]标题误导,请修正。这将使其他答案无效,但您应该这样做。 - EKons

2
如果我们足够费尽心思,我们可以得出一个不同之处。但它是模糊的并涉及未定义的行为,因此如果我们关心的只是代码是否严格符合ISO C标准,那么这并不重要。
使用#if defined ...形式可能会在先前处理了#define defined ... 宏时表现得不同。 ISO C99标准中写道:

在评估之前,将成为控制常量表达式的预处理令牌列表中的宏调用被替换(除了由defined一元运算符修改的那些宏名称),就像在正常文本中一样。

并没有要求识别defined一元运算符并保护其免受被视为宏的影响;它只是“将成为...表达式”的“预处理令牌”之一。 该操作符仅出于保护其参数免受扩展而在该阶段被识别。
如果将define的定义作为宏来处理,并且随后替换defined的出现次数(包括在#if预处理指令的参数中),从而干扰#if defined,而不影响#ifdef
也许自C99以来,语言领域的这个区域已经得到了加强。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接