命名空间
变体
操作

条件包含

来自 cppreference.cn
 
 
C++ 语言
 
预处理器
#if#ifdef#ifndef#else#elif#elifdef#elifndef#endif
(C++23)(C++23)
(C++26)
 

预处理器支持源文件部分的条件编译。此行为由 #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

表达式可能包含

  • 形式为 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 issue 1955 解决之前,#if cond1 ... #elif cond2#if cond1 ... #else 后跟 #if cond2 不同,因为如果 cond1 为真,则第二个 #if 被跳过,并且 cond2 不需要格式良好,而 #elifcond2 必须是有效表达式。根据 CWG 1955,导致跳过代码块的 #elif 也被跳过。

[编辑] 组合指令

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

#ifdef 标识符 本质上等价于 #if defined 标识符

#ifndef 标识符 本质上等价于 #if !defined 标识符

#elifdef 标识符 本质上等价于 #elif defined 标识符

#elifndef 标识符 本质上等价于 #elif !defined 标识符

(C++23 起)

[编辑] 注意

虽然 #elifdef#elifndef 指令面向 C++23,但鼓励实现将它们回溯移植到较旧的语言模式作为符合标准的扩展。

[编辑] 示例

#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

[编辑] 缺陷报告

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

缺陷报告 应用于 发布时的行为 正确的行为
CWG 1955 C++98 失败的 #elif 的表达式被要求是有效的 失败的 #elif 被跳过

[编辑] 参阅

C 文档 关于 条件包含