预处理器支持有条件地编译源文件的某些部分。这一行为由 #if#else#elif#ifdef#ifndef#endif 指令所控制。

语法

#if 表达式
#ifdef 标识符
#ifndef 标识符
#elif 表达式
#else
#endif

解释

条件编译预处理块由 #if#ifdef#ifndef 指令开始,并可选地包含任意多个 #elif 指令,接下来是至多一个可选的 #else 指令,并以 #endif 指令结束。嵌套的条件编译预处理块会被单独处理。

各个 #if#elif#else#ifdef#ifndef 指令所控制的代码块在第一个不属于内部嵌套的条件编译预处理块的 #elif#else#endif 指令处结束。

#if#ifdef#ifndef 指令测试其所指定的条件(见下文),如果条件求值为真,则编译其控制的代码块。此时后续的 #else#elif 指令将被忽略。否则,如果所指定的条件求值为假,则将跳过其所控制的代码块,然后处理后续的 #else#elif 指令(如果存在)。前一种情况下,#else 指令所控制的代码块将会无条件地进行编译。后一种情况下,#elif 指令按照与 #if 指令相同的方式执行:即测试条件是否满足,并根据其结果决定编译或跳过其所控制的代码块,并在后一种情况下继续处理后续的 #elif#else 指令。条件编译预处理块以 #endif 指令结束。

条件的求值

#if, #elif

表达式 是常量表达式。

表达式可含有形如“defined 标识符”或“defined (标识符)”的一元运算符。当此 标识符 已经被定义为宏名,或者此 标识符 为 __has_include (C++17 起)时结果为 1,否则结果为 ​0​。

在进行所有宏展开和 defined__has_include (C++17 起) 表达式的求值后,任何非布尔字面量的标识符都被替换成数字 ​0​(这包含词法上为关键字的标识符,但不包括如 and 之类的代用记号)。

当 表达式 求值为非零值时,包含其所控制的代码块,否则跳过该代码块。


注:“#if cond1#elif cond2”和“#if cond1#else”后面跟着“#if cond3”是不同的,因为当 cond1 为真时第二个 #if 将被跳过,且 cond3 并不需要是良构的,而 #elif 中的 cond2 则必须是合法的表达式。
(C++14 前)

#ifdef, #ifndef

检查标识符是否被定义为宏名

#ifdef 标识符”与“#if defined 标识符”实质上等价。

#ifndef 标识符”与“#if !defined 标识符”实质上等价。

示例

运行此代码

  1. #define ABCD 2
  2. #include <iostream>
  3.  
  4. int main()
  5. {
  6.  
  7. #ifdef ABCD
  8. std::cout << "1: yes\n";
  9. #else
  10. std::cout << "1: no\n";
  11. #endif
  12.  
  13. #ifndef ABCD
  14. std::cout << "2: no1\n";
  15. #elif ABCD == 2
  16. std::cout << "2: yes\n";
  17. #else
  18. std::cout << "2: no2\n";
  19. #endif
  20.  
  21. #if !defined(DCBA) && (ABCD < 2*4-3)
  22. std::cout << "3: yes\n";
  23. #endif
  24. }

输出:

  1. 1: yes
  2. 2: yes
  3. 3: yes

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR 应用于 出版时的行为 正确行为
CWG 1955 C++14 要求失败的 #elif 中的表达式合法 跳过失败的 elif