Conditional inclusion
预处理器支持对源文件部分内容进行条件编译。该行为由
#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
。
|
在预处理器指令的上下文中,
|
(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
。
|
|
(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++ 文档
关于
条件包含
|