目的用什么 #ifdef,#if C++

What does purpose use #ifdef and #if in C++

本文关键字:#if C++ #ifdef 什么      更新时间:2023-10-16

在我的项目代码中,我发现有人在代码中使用了#ifdef#if。我想知道使用它们的目的是什么?据我所知,它对预处理器说不会在该代码中执行任何操作。下面的代码给出了两个使用它们的示例。我试图找到TEST_PURPOSE的定义(真/假(,但它找不到。从下面的代码中,如何在#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

#ifdef的意思是,只有定义了提到的预处理器宏,块中的代码才会包含在编译中。同样,#if 表示仅当表达式的计算结果为 true 时(将表达式中显示的未定义宏替换为 0 时(,才会包含该块。

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

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

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

#ifndef HEADER_INCLUDED_
#define HEADER_INCLUDED_
// actual payload of the header file
#endif

此外,在文件的解析和编译需要很长时间的时候,这可能会导致加速,因为可以快速跳过标头的有效负载(预处理阶段处理源代码的速度比实际编译阶段快得多(。

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

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

#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()语句有区别,
如本例所示,二进制文件中将仅包含一个代码。


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

#ifdef表示如果定义。 如果定义了#ifdef后面的符号(使用前面源代码中的 #define 或使用编译器命令行参数(,则预处理器将包含到封闭 #endif 的文本,并因此进行编译。

#if的工作方式类似,但它计算其后面的布尔表达式。 如果该表达式为 true,则包含到封闭#endif的代码。

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

我相信你已经看到了头球卫

#ifndef X_H
#define X_H
...
#endif

这可以防止多次包含标头。

这些是相同的。如果您定义了TEST_PURPOSE(通过 #define TEST_PURPOSE(,您将获得受 #ifdef TEST_PURPOSE 保护的代码块。#if 0永远不会包括在内,可能也用于测试。

#if 0
...
#endif

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

#ifdef TEST_PURPOSE
...
#endif

另一方面,包含基于是否定义预处理器宏TEST_PURPOSE而包含/排除的代码。

如何在#ifdef TEST_PURPOSE内部做某事

这很简单:定义TEST_PURPOSE .执行此操作的典型位置是作为命令行参数、修改公共标头,或者在适当时,在包含出现此标头文件的标头文件之前进行定义。

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

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