条件付きインクルージョン
プリプロセッサは、ソースファイルの一部を条件付きでコンパイルすることをサポートしています。この動作は、#if、#else、#elif、#ifdef、#ifndefディレクティブ、および#endifディレクティブによって制御されます。#elifdef、#elifndef(C23以降)も含まれます。
目次 |
[編集] 構文
#if 式 |
|||||||||
#ifdef 識別子 |
|||||||||
#ifndef 識別子 |
|||||||||
#elif 式 |
|||||||||
#elifdef 識別子 |
(C23以降) | ||||||||
#elifndef 識別子 |
(C23以降) | ||||||||
#else
|
|||||||||
#endif
|
|||||||||
[編集] 説明
条件付きプリプロセッサブロックは、#if、#ifdef、または#ifndefディレクティブで開始され、その後、任意の数の#elif(C23以降)、#elifdef、または#elifndefディレクティブがオプションで続き、最大1つの#elseディレクティブがオプションで続き、#endifディレクティブで終了します。内部の条件付きプリプロセッサブロックは個別に処理されます。
#if、#ifdef、#ifndef、#elif(C23以降)、#elifdef、#elifndef、および#elseディレクティブは、最初の#elif(C23以降)、#elifdef、#elifndef、#else、#endifディレクティブ(内部の条件付きプリプロセッサブロックに属さないもの)までのコードブロックを制御します。
#if、#ifdef、#ifndefディレクティブは、指定された条件(下記参照)をテストし、それが真と評価された場合は、制御されたコードブロックをコンパイルします。この場合、後続の#else(C23以降)、#elifdef、#elifndef、および#elifディレクティブは無視されます。それ以外の場合、指定された条件が偽と評価された場合、制御されたコードブロックはスキップされ、後続の#else(C23以降)、#elifdef、#elifndef、または#elifディレクティブ(存在する場合)が処理されます。後続のディレクティブが#elseの場合、#elseディレクティブによって制御されるコードブロックは無条件にコンパイルされます。それ以外の場合、#elif(C23以降)、#elifdef、または#elifndefディレクティブは、#ifディレクティブのように動作します。つまり、条件をチェックし、結果に基づいて制御されたコードブロックをコンパイルまたはスキップし、後者の場合は後続の#elif(C23以降)、#elifdef、#elifndef、および#elseディレクティブを処理します。条件付きプリプロセッサブロックは#endifディレクティブで終了します。
[編集] 条件付き評価
[編集] #if, #elif
式は、定数と、 #define ディレクティブを使用して定義された識別子のみを使用する定数式です。#defineディレクティブで定義されていないリテラルでない識別子は、0と評価されます(C23以降では、trueは1と評価されます)。
式には、defined 識別子またはdefined (識別子)の形式の単項演算子を含めることができます。これは、識別子が #define ディレクティブを使用して定義されている場合は1を返し、そうでない場合は0を返します。C23以降では、このコンテキストでは、__has_include、__has_embed、および__has_c_attributeは、定義されたマクロの名前として扱われます。式がゼロ以外の値を評価した場合、制御されたコードブロックは含まれ、それ以外の場合はスキップされます。使用されている識別子が定数でない場合、0に置き換えられます。
|
プリプロセッサディレクティブのコンテキストでは、 |
(C23以降) |
注:DR 412まで、#if cond1 ... #elif cond2は、#if cond1 ... #elseに続いて#if cond3とは異なっていました。なぜなら、cond1が真の場合、2番目の#ifはスキップされ、cond3は有効である必要がなかったのに対し、#elifのcond2は有効な式である必要があったからです。DR 412以降、スキップされたコードブロックに続く#elifもスキップされます。
[編集] 複合ディレクティブ
識別子がマクロ名として定義されているかどうかをチェックします。
#ifdef 識別子は、実質的に#if defined 識別子と同等です。
#ifndef 識別子は、実質的に#if !defined 識別子と同等です。
|
|
(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++ ドキュメント(条件付きインクルージョン)
|