#if、#elif、#else 和 #endif 指示詞 (C/C++)

具有 #elif #else #endif 指示詞的 #if 指示詞,可控制原始程式檔部分的編譯。 如果您撰寫的 運算式(在 #if 之後)有非零值,則緊接在 翻譯單位中保留 #if 指示詞後面的行群組。

文法

條件
if-part elif-parts opt else-part opt endif-line

if-part
if-line 文字

if-line
#if常數運算式
#ifdef識別碼
#ifndef識別碼

elif-parts
elif-line 文字
elif-parts elif-line text

elif-line
#elif constant-expression

else-part
else-line text

else-line
#else

endif-line
#endif

備註

原始程式檔中的每個 #if 指示詞都必須比對結尾 #endif 指示詞。 任何數目 的 #elif 指示詞都可以出現在 #if #endif 指示詞之間 ,但最多允許一個 #else 指示詞。 如果存在,則 #else 指示詞必須是 #endif 之前的 最後一個指示詞。

#if #elif #else #endif 指示詞可以在其他 #if 指示詞的文字 部分中巢 狀。 每個巢狀 #else #elif #endif 指示詞都屬於最接近的先前 #if 指示詞。

所有條件式編譯指示詞,例如 #if #ifdef ,都必須在檔案結尾之前比對結尾 #endif 指示詞。 否則,會產生錯誤訊息。 當 Include 檔包含條件式編譯指示詞時,這些指示詞必須滿足相同的條件:include 檔結尾不可以有不相符的條件式編譯指示詞。

宏取代是在 #elif 命令之後 行的一部分完成,因此可以在 constant-expression 中使用 呼叫。

預處理器會選取其中一個指定的文字 出現專案 ,以便進一步處理。 文字 中指定的 區塊可以是任何序列的文字。 可能會佔用一行以上。 通常 文字 是程式文字,對編譯器或預處理器具有意義。

預處理器會處理選取 的文字 ,並將它傳遞給編譯器。 如果 text 包含預處理器指示詞,預處理器會執行這些指示詞。 只會編譯前置處理器選取的文字區塊。

預處理器會藉由評估每個 #if 或 #elif 指示詞後面的常數運算式來選取單 一文字 專案,直到找到 true (非零) 常數運算式為止。 它會選取所有文字(包括開頭 # 為 的其他預處理器指示詞),最多到其相關聯的 #elif #else #endif

如果所有出現的 常數運算式 都是 false,或者沒有 出現任何 #elif 指示詞,預處理器會在 #else 子句後面 選取文字區塊。 如果沒有 #else 子句,且 #if 區塊中的所有 常數運算式 實例 為 false,則不會選取任何文字區塊。

constant-expression 是具有下列額外限制的整數常數運算式:

  • 運算式必須具有整數類型,而且只能包含整數常數、字元常數和 定義的 運算子。

  • 運算式無法使用 sizeof 或類型轉換運算子。

  • 目標環境可能無法代表整數的所有範圍。

  • 此轉譯代表類型與 型 int 別相同, longunsigned int 相同方式。 unsigned long

  • 轉譯器可以將字元常數轉譯為一組與目標環境的一組程式碼值不同的程式碼值。 若要判斷目標環境的屬性,請使用針對該環境建置的應用程式來檢查 LIMITS 的值 。H 宏。

  • 運算式不得查詢環境,而且必須與目的電腦上的實作詳細資料保持隔離。

前置處理器運算子

已定義的

定義的 預處理器運算子 可用於特殊常數運算式,如下列語法所示:

defined( identifier
已定義識別碼

如果識別碼目前已定義, 這個常數運算式會被視為 true (非零)。 否則,條件為 false (0)。 定義成空白文字的識別項會被視為已定義。 定義的 運算子可用於 #if #elif 指示詞,但無處可去。

在下列範例中 ,#if #endif 指示詞會控制三個函式呼叫之一的編譯:

#if defined(CREDIT)
    credit();
#elif defined(DEBIT)
    debit();
#else
    printerror();
#endif

如果識別項 credit 已定義,就會編譯 CREDIT 的函式呼叫。 如果識別項 DEBIT 已定義,就會編譯 debit 的函式呼叫。 如果這些識別項都未定義,就會編譯 printerror 的呼叫。 CREDITcredit 都是 C 和 C++ 中的相異識別碼,因為它們的案例不同。

在下列範例中的條件式編譯陳述式假設先前定義名為 DLEVEL 的符號常數。

#if DLEVEL > 5
    #define SIGNAL  1
    #if STACKUSE == 1
        #define STACK   200
    #else
        #define STACK   100
    #endif
#else
    #define SIGNAL  0
    #if STACKUSE == 1
        #define STACK   100
    #else
        #define STACK   50
    #endif
#endif
#if DLEVEL == 0
    #define STACK 0
#elif DLEVEL == 1
    #define STACK 100
#elif DLEVEL > 5
    display( debugptr );
#else
    #define STACK 200
#endif

第一個 #if 區塊會顯示兩組巢狀 #if #else #endif 指示詞。 只有在 DLEVEL > 5 為 true 時,才會處理第一組指示詞。 否則,處理 #else 之後 的 語句。

二個範例中的 #elif #else 指示詞是用來根據 的值 DLEVEL 進行四個選項之一。 常數 STACK 會設為 0、100 或 200,視 DLEVEL 的定義而定。 如果 DLEVEL 大於 5,則陳述式

#elif DLEVEL > 5
display(debugptr);

已編譯,且 STACK 未定義。

條件式編譯的常見用途是防止多次包含相同的標頭檔。 在 C++ 中,類別通常定義于標頭檔中,這類建構可用來防止多個定義:

/*  EXAMPLE.H - Example header file  */
#if !defined( EXAMPLE_H )
#define EXAMPLE_H

class Example
{
    //...
};

#endif // !defined( EXAMPLE_H )

上述程式碼會檢查符號常數 EXAMPLE_H 是否已定義。 如果是,檔案已經包含,而且不需要重新處理。 否則會定義常數 EXAMPLE_H 以便將 EXAMPLE.H 標記為已經處理。

__has_include

Visual Studio 2017 15.3 版和更新版本 :判斷程式庫標頭是否可供包含:

#ifdef __has_include
#  if __has_include(<filesystem>)
#    include <filesystem>
#    define have_filesystem 1
#  elif __has_include(<experimental/filesystem>)
#    include <experimental/filesystem>
#    define have_filesystem 1
#    define experimental_filesystem
#  else
#    define have_filesystem 0
#  endif
#endif

另請參閱

預處理器指示詞