条件包含
预处理器支持对源文件部分进行条件编译。 此行为由 #if
、#else
、#elif
、#ifdef
、#ifndef
、#elifdef
、#elifndef
(自 C++23 起) 和 #endif
指令控制。
内容 |
[编辑] 语法
#if 表达式 |
|||||||||
#ifdef 标识符 |
|||||||||
#ifndef 标识符 |
|||||||||
#elif 表达式 |
|||||||||
#elifdef 标识符 |
(自 C++23 起) | ||||||||
#elifndef 标识符 |
(自 C++23 起) | ||||||||
#else
|
|||||||||
#endif
|
|||||||||
[编辑] 说明
条件预处理块以 #if
、#ifdef
或 #ifndef
指令开头,然后可选地包含任意数量的 #elif
、#elifdef
或 #elifndef
(自 C++23 起) 指令,然后可选地包含最多一个 #else
指令,最后以 #endif
指令结束。 任何内部条件预处理块将单独处理。
每个 #if
、#ifdef
、#ifndef
、#elif
、#elifdef
、#elifndef
(自 C++23 起) 和 #else
指令控制代码块,直到第一个不属于任何内部条件预处理块的 #elif
、#elifdef
、#elifndef
(自 C++23 起)、#else
、#endif
指令。
#if
、#ifdef
和 #ifndef
指令测试指定的条件(见下文),如果它计算为真,则编译受控代码块。 在这种情况下,随后的 #else
、#elifdef
、#elifndef
、(自 C++23 起) 和 #elif
指令将被忽略。 否则,如果指定的条件计算为假,则受控代码块将被跳过,并且将处理随后的 #else
、#elifdef
、#elifndef
、(自 C++23 起) 或 #elif
指令(如果有)。 如果随后的指令是 #else
,则由 #else
指令控制的代码块将无条件编译。 否则,#elif
、#elifdef
或 #elifndef
(自 C++23 起) 指令的行为就像 #if
指令:检查条件,根据结果编译或跳过受控代码块,并在后一种情况下处理随后的 #elif
、#elifdef
、#elifndef
、(自 C++23 起) 和 #else
指令。 条件预处理块由 #endif
指令终止。
[编辑] 条件评估
[编辑] #if, #elif
The expression may contain
- 一元运算符,形式为
defined
标识符 或defined (
标识符)
。如果 标识符 被定义为宏名称,则结果为 1,否则结果为 0。__has_include
和__has_cpp_attribute
(自 C++20 起) 在此上下文中被视为已定义宏的名称。(自 C++17 起) - (自 C++17 起) __has_include 表达式,用于检测头文件或源文件是否存在。
- (自 C++20 起) __has_cpp_attribute 表达式,用于检测给定属性标记是否受支持及其支持的版本。
在所有宏展开和 defined
、 __has_include
(自 C++17 起)、 __has_cpp_attribute
(自 C++20 起) 表达式求值之后,任何不是 布尔文字 的标识符都将替换为数字 0(这包括在词法上是关键字的标识符,但不包括像 and 这样的备用标记)。
然后,表达式将被评估为 整型常量表达式。
如果 表达式 的计算结果为非零值,则包含控制代码块,否则跳过。
注意:在解决 CWG 问题 1955 之前,#if cond1
... #elif cond2
与 #if cond1
... #else
后面跟着 #if cond2
不同,因为如果 cond1
为真,则第二个 #if
将被跳过,cond2
不需要是格式良好的,而 #elif
的 cond2
必须是有效的表达式。根据 CWG 1955,导致跳过代码块的 #elif
也将被跳过。
[edit] 组合指令
检查标识符是否 被定义为宏名称。
#ifdef
标识符 本质上等效于 #if defined
标识符。
#ifndef
标识符 本质上等效于 #if !defined
标识符。
|
(自 C++23 起) |
[edit] 注意
虽然 #elifdef
和 #elifndef
指令针对 C++23,但鼓励实现将它们作为符合扩展移植到旧的语言模式。
[edit] 示例
#define ABCD 2 #include <iostream> int main() { #ifdef ABCD std::cout << "1: yes\n"; #else std::cout << "1: no\n"; #endif #ifndef ABCD std::cout << "2: no1\n"; #elif ABCD == 2 std::cout << "2: yes\n"; #else std::cout << "2: no2\n"; #endif #if !defined(DCBA) && (ABCD < 2*4-3) std::cout << "3: yes\n"; #endif // Note that if a compiler does not support C++23's #elifdef/#elifndef // directives then the "unexpected" block (see below) will be selected. #ifdef CPU std::cout << "4: no1\n"; #elifdef GPU std::cout << "4: no2\n"; #elifndef RAM std::cout << "4: yes\n"; // expected block #else std::cout << "4: no!\n"; // unexpectedly selects this block by skipping // unknown directives and "jumping" directly // from "#ifdef CPU" to this "#else" block #endif // To fix the problem above we may conditionally define the // macro ELIFDEF_SUPPORTED only if the C++23 directives // #elifdef/#elifndef are supported. #if 0 #elifndef UNDEFINED_MACRO #define ELIFDEF_SUPPORTED #else #endif #ifdef ELIFDEF_SUPPORTED #ifdef CPU std::cout << "4: no1\n"; #elifdef GPU std::cout << "4: no2\n"; #elifndef RAM std::cout << "4: yes\n"; // expected block #else std::cout << "4: no3\n"; #endif #else // when #elifdef unsupported use old verbose `#elif defined` #ifdef CPU std::cout << "4: no1\n"; #elif defined GPU std::cout << "4: no2\n"; #elif !defined RAM std::cout << "4: yes\n"; // expected block #else std::cout << "4: no3\n"; #endif #endif }
可能的输出
1: yes 2: yes 3: yes 4: no! 4: yes
[edit] 缺陷报告
以下行为更改缺陷报告被追溯应用于先前发布的 C++ 标准。
DR | 应用于 | 发布时的行为 | 正确行为 |
---|---|---|---|
CWG 1955 | C++98 | 失败的 #elif 表达式要求有效 | 失败的 #elif 被跳过 |
[edit] 另请参阅
C 文档 针对 条件包含
|