在C ++中使用#ifdef和#if的目的是什么

时间:2015-10-14 05:26:59

标签: c++ visual-studio

在我的项目代码中,我发现有人在代码中使用了#ifdef#if。我想知道使用它们的目的是什么?据我所知,它说预处理器不会在代码中做任何事情。下面的代码给出了两个使用它们的示例。我试图找到TEST_PURPOSE(true / false)的定义,但找不到。从下面的代码,如何在#ifdef TEST_PURPOSE内做一些事情?我正在使用visual studio 2012

#ifdef TEST_PURPOSE
    int i=1;
    printf("Something %d,"i);
#endif

#if 0
  int i=1;
  printf("Something %d,"i);
#endif

7 个答案:

答案 0 :(得分:4)

#ifdef的含义是,只有在定义了所提到的预处理器宏时,块内的代码才会包含在编译中。类似#if意味着仅当表达式求值为true时才会包含该块(当替换表达式中出现的未定义宏时为0)。

这里的一个重点是预处理器在编译之前处理源,如果不包含该块,则实际编译器根本不会对其进行解析。这是构造的一个重要特征。

现在由于某种原因,C / C ++使用它。这些语言以线性顺序处理文件,因此在源代码下方显示的内容尚不清楚,而其他源文件中出现的更重要的内容也是如此。这意味着没有(好的)自动方式可以在另一个源文件中引用一个源文件中的符号,尤其是如果您希望类型正确的话。这意味着您必须拥有原型和extern定义才能引用这些定义。此外,两个源文件应共享数据类型(structenum s)的情况也是如此。

为了使其更实用,可以将这些放在头文件中,每个源文件都可以#include(这基本上意味着将头文件插入到实际编译器看到的内容中)。这反过来容易导致一个头文件包含另一个头文件的情况,并且您可能遇到两次包含相同文件的情况。由于重复struct定义无效,因此需要确保相同的头文件未定义两次 - 其中#ifndef在包含保护中很方便:

#ifndef HEADER_INCLUDED_
#define HEADER_INCLUDED_

// actual payload of the header file

#endif

此外,在解析和编译文件需要很长时间的情况下,这可能会导致加速,因为可以快速跳过标头的有效负载(预处理阶段比实际编译阶段更快地处理源)

需要的另一个原因"宏是早期的C编译器可能只是直接将代码转换为汇编程序。您可以通过使用宏来避免函数调用,这将导致它的扩展将直接插入到现场并在那里生成代码而不必进行函数调用。同样的事情适用于常量,否则这些常量必须在其他地方获取而不是直接放入生成的代码中。

第三个原因是条件编译的可能性。大多数编译器预定义了一组宏,这些宏旨在提供有关正在编译的系统的信息。例如,我们有宏_WIN32,只有在您为Windows编译时才会定义它。这样就可以拥有一个仅包含在Windows中的代码片段和另一个代码片段,如果它是另一个平台的话。大多数编译器也可以从命令行设置自定义宏,这意味着可以从命令行(在Visual Studio中,您也可以在项目设置中更改它们)更改将要编译的部分。最引人注目的宏是NDEBUG宏,如果定义将禁用所有assert - 在编译版本构建时添加/DNDEBUG是正常的。

答案 1 :(得分:2)

#ifdef表示,如果已定义。如果定义了#ifdef之后的符号,或者使用先前源代码中的#define或使用编译器命令行参数,则预处理器将包含#endif的文本包含在内,然后进行编译。

#if的工作方式类似,但它会计算跟随它的布尔表达式。如果该表达式为真,则包含封闭#endif的代码。

答案 2 :(得分:2)

  

如何在#ifdef TEST_PURPOSE

中执行某些操作

这很简单:定义TEST_PURPOSE。这样做的典型位置是命令行参数,修改公共标题,或者在适当的时候,在包含出现的头文件之前进行定义。

答案 3 :(得分:1)

这些是预编译器指令。 C ++预编译器最初来自C(不确定它现在是否不同)允许您根据您定义的变量或常量更改编译器将看到的文本。

我确定你已经看到了标题警卫

#ifndef X_H
#define X_H

...

#endif

可防止多次包含标题。

这些都是一样的。如果您TEST_PURPOSE已定义(#define TEST_PURPOSE),您将获得受#ifdef TEST_PURPOSE保护的代码块。 #if 0永远不会被包括在内,也可能用于测试。

答案 4 :(得分:1)

#if 0
...
#endif

是排除大块代码被编译的一种方法。它就像一大堆注释掉的代码。

#ifdef TEST_PURPOSE
...
#endif
另一方面,

包含根据是否定义了预处理器宏TEST_PURPOSE而包含/排除的代码。

答案 5 :(得分:1)

#ifdef检查之后的名称是否为#define d。如果检查失败,将忽略#ifdef#endif之间的代码。

可以通过在#define TEST_PURPOSE之前显式写#ifdef,或将/D "TEST_PURPOSE"作为参数传递给MSVC编译器来完成检查。如果您使用的是Visual Studio,则可以在项目配置中进行设置,以便您可以轻松地打开和关闭它。

答案 6 :(得分:1)

#ifdef#if是预处理器指令,在代码编译之前会对它们进行评估。
预处理器指令有很多用途, 在您的示例中:#ifdef#if用于包含或排除代码的某些部分进行编译。

强调:完全排除在构建过程中不存在!
你可以在一个不活跃的预处理器块中乱搞。

注意#if defined(A)#ifdef A相同,因此我仅提及#if

使用1 - 禁用通过链包含处理相同的头文件。

最常见的用途是“头部防护”:
通过#include链,您可能会重新输入相同的H文件并产生无法预料的现象,因此,使用以下构造非常常见

#if !defined(MyHeader_H)
#define MyHeader_H

...

#endif

开始时,MyHeader_H不会定义构造,将被处理, 包括MyHeader_H ...
在后续调用中,#ifndef MyHeader_H false ,H文件不会包含在模块中。

使用2 - 定义配置

有些项目有几种配置,假设使用不同的硬件类型或一些不同的行为。

你可以写像:

#if defined(FLASH_TYPE_A)
code to use flash type A
#elif defined (FLASH_TYPE_B)
code to use flash type B
#else 
ASSERT("NO FLASH TYPE DEFINED!");
#endif

在此代码中,您可以在编译期间使用/dFLASH_TYPE_A/dFLASH_TYPE_B来定义将包含哪些代码...

注意:与使用标准if()声明有区别,
如本例所示,二进制文件中只包含一个代码。

有更多用途,但我认为这些是最常见的用途!