名稱空間
變體
操作

條件包含

來自 cppreference.com
 
 
C++ 語言
 
預處理器
#if#ifdef#ifndef#else#elif#elifdef#elifndef#endif
(C++23)(C++23)
(C++26)
 

預處理器支援原始檔部分的條件編譯。此行為由 #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 不需要格式良好,而 #elifcond2 必須是有效表示式。根據 CWG 1955,導致跳過程式碼塊的 #elif 也被跳過。

[編輯] 組合指令

檢查識別符號是否被定義為宏名稱

#ifdef 識別符號 本質上等價於 #if defined 識別符號

#ifndef 識別符號 本質上等價於 #if !defined 識別符號

#elifdef 識別符號 本質上等價於 #elif defined 識別符號

#elifndef 識別符號 本質上等價於 #elif !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 文件 關於 條件包含