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以降)
ディレクティブを任意の数だけ含み、任意で最大1つの
#else
ディレクティブを含み、
#endif
ディレクティブで終了します。内部の条件付きプリプロセスブロックは個別に処理されます。
#if
、
#ifdef
、
#ifndef
、
#elif
、
#elifdef
、
#elifndef
(C23以降)
および
#else
ディレクティブはそれぞれ、最初の
#elif
、
#elifdef
、
#elifndef
(C23以降)
、
#else
、
#endif
ディレクティブに到達するまでのコードブロックを制御します。ただし、内側の条件付きプリプロセスブロックに属さないものに限ります。
#if
、
#ifdef
および
#ifndef
ディレクティブは指定された条件(後述)を評価し、真と評価された場合、制御されるコードブロックをコンパイルします。この場合、後続の
#else
、
#elifdef
、
#elifndef
、
(C23以降)
および
#elif
ディレクティブは無視されます。それ以外の場合、指定された条件が偽と評価されると、制御されるコードブロックはスキップされ、後続の
#else
、
#elifdef
、
#elifndef
、
(C23以降)
または
#elif
ディレクティブ(存在する場合)が処理されます。後続のディレクティブが
#else
の場合、
#else
ディレクティブによって制御されるコードブロックは無条件でコンパイルされます。それ以外の場合、
#elif
、
#elifdef
または
#elifndef
(C23以降)
ディレクティブは
#if
ディレクティブと同様に動作します:条件をチェックし、結果に基づいて制御されるコードブロックをコンパイルまたはスキップし、後者の場合、後続の
#elif
、
#elifdef
、
#elifndef
、
(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
に置き換えられます。
|
プリプロセッサ指令の文脈において、
|
(C23以降) |
注:
DR 412
以前は、
#if
cond1
...
#elif
cond2
と
#if
cond1
...
#else
に続く
#if
cond3
は異なっていました。なぜなら、
cond1
が真の場合、2番目の
#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 | 適用対象 | 公開時の動作 | 正しい動作 |
|---|---|---|---|
| DR 412 | C89 |
失敗した
#elif
の式は有効であることが要求されていた
|
失敗した
#elif
はスキップされる
|
参考文献
- C23規格 (ISO/IEC 9899:2024):
-
- 6.10.1 条件付き取り込み (p: TBD)
- C17規格 (ISO/IEC 9899:2018):
-
- 6.10.1 条件付きインクルージョン (p: 118-119)
- C11規格 (ISO/IEC 9899:2011):
-
- 6.10.1 条件付きインクルージョン (p: 162-164)
- C99標準 (ISO/IEC 9899:1999):
-
- 6.10.1 条件付きインクルージョン (p: 147-149)
- C89/C90標準 (ISO/IEC 9899:1990):
-
- 3.8.1 条件付きインクルージョン
関連項目
|
C++ documentation
for
条件付きインクルード
|