條件包含
預處理器支援原始檔部分的條件編譯。此行為由 #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
不需要格式良好,而 #elif
的 cond2
必須是有效表示式。根據 CWG 1955,導致跳過程式碼塊的 #elif
也被跳過。
[編輯] 組合指令
檢查識別符號是否被定義為宏名稱。
#ifdef
識別符號 本質上等價於 #if defined
識別符號。
#ifndef
識別符號 本質上等價於 #if !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 文件 關於 條件包含
|