Namespaces
Variants

Conditional inclusion

From cppreference.net

预处理器支持对源文件部分内容进行条件编译。该行为由 #if #else #elif #ifdef #ifndef #elifdef #elifndef (C23起) #endif 指令控制。

目录

语法

#if 表达式
#ifdef 标识符
#ifndef 标识符
#elif 表达式
#elifdef 标识符 (自 C23 起)
#elifndef 标识符 (自 C23 起)
#else
#endif

说明

条件预处理块以 #if #ifdef #ifndef 指令开始,随后可选择包含任意数量的 #elif #elifdef #elifndef (C23起) 指令,然后最多包含一个 #else 指令,并以 #endif 指令终止。所有内部条件预处理块都会独立处理。

每个 #if #ifdef #ifndef #elif #elifdef #elifndef (C23 起) #else 指令控制代码块,直到遇到第一个不属于任何内部条件预处理块的 #elif #elifdef #elifndef (C23 起) #else #endif 指令。

#if #ifdef #ifndef 指令测试指定条件(见下文),若评估为真,则编译受控代码块。此时后续的 #else #elifdef #elifndef (since C23) #elif 指令将被忽略。否则,若指定条件评估为假,则跳过受控代码块并处理后续的 #else #elifdef #elifndef (since C23) #elif 指令(若存在)。若后续指令为 #else ,则 #else 指令控制的代码块将被无条件编译。否则, #elif #elifdef #elifndef (since C23) 指令的行为与 #if 指令类似:检查条件,根据结果编译或跳过受控代码块,并在后一种情况下处理后续的 #elif #elifdef #elifndef (since C23) #else 指令。条件预处理块由 #endif 指令终止。

条件求值

#if, #elif

表达式 是常量表达式,仅使用 常量 和通过 #define 指令定义的标识符。任何非字面量且未通过 #define 指令定义的标识符,其求值结果为 0 ,但 true 的求值结果为 1 除外 (C23起)

表达式可能包含形式为 defined identifier defined ( identifier ) 的一元运算符,若该 identifier 已通过 #define 指令定义则返回 1 ,否则返回 0 在此上下文中, __has_include __has_embed __has_c_attribute 会被视为已定义的宏名称。 (C23 起) expression 求值为非零值,则受控代码块会被包含,否则被跳过。若任何使用的标识符不是常量,则会被替换为 0

在预处理器指令的上下文中, __has_c_attribute 表达式用于检测给定的属性标记是否受支持及其受支持的版本。详见 属性测试

(since C23)

注意:在 DR 412 之前, #if cond1 ... #elif cond2 #if cond1 ... #else 后接 #if cond3 有所不同,因为如果 cond1 为真,第二个 #if 会被跳过,此时 cond3 不需要是合法表达式,而 #elif cond2 必须是合法表达式。自 DR 412 起,导致代码块被跳过的 #elif

组合指令

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

#ifdef identifier 本质上等同于 #if defined identifier

#ifndef identifier 本质上等同于 #if !defined identifier

#elifdef identifier 本质上等价于 #elif defined identifier

#elifndef identifier 本质上等价于 #elif !defined identifier

(C23 起)

注释

虽然 #elifdef #elifndef 指令的目标是 C23 标准,但实现可能会将它们作为符合规范的扩展向后移植到较旧的语言模式中。

示例

#define ABCD 2
#include <stdio.h>
int main(void)
{
#ifdef ABCD
    printf("1: yes\n");
#else
    printf("1: no\n");
#endif
#ifndef ABCD
    printf("2: no1\n");
#elif ABCD == 2
    printf("2: yes\n");
#else
    printf("2: no2\n");
#endif
#if !defined(DCBA) && (ABCD < 2 * 4 - 3)
    printf("3: yes\n");
#endif
// C23 directives #elifdef/#elifndef
#ifdef CPU
    printf("4: no1\n");
#elifdef GPU
    printf("4: no2\n");
#elifndef RAM
    printf("4: yes\n"); // selected in C23 mode, may be selected in pre-C23 mode
#else
    printf("4: no3\n"); // may be selected in pre-C23 mode
#endif
}

可能的输出:

1: yes
2: yes
3: yes
4: yes

缺陷报告

下列行为变更缺陷报告被追溯应用于先前发布的C语言标准。

缺陷报告 适用范围 发布时行为 正确行为
DR 412 C89 要求失败的 #elif 表达式必须有效 失败的 #elif 会被跳过

参考文献

  • C23 标准 (ISO/IEC 9899:2024):
  • 6.10.1 条件包含 (p: TBD)
  • C17 标准 (ISO/IEC 9899:2018):
  • 6.10.1 条件性包含 (页码: 118-119)
  • C11 标准 (ISO/IEC 9899:2011):
  • 6.10.1 条件包含 (p: 162-164)
  • C99标准(ISO/IEC 9899:1999):
  • 6.10.1 条件包含(页码:147-149)
  • C89/C90 标准 (ISO/IEC 9899:1990):
  • 3.8.1 条件包含

参见

C++ 文档 关于 条件包含