#if、#elif、#else 和 #endif 指示詞 (C/C++)
具有 #elif、#else 和 #endif 指示詞的 #if 指示詞,可控制原始程序檔部分的編譯。 如果您撰寫的 表達式(在 #if 之後)有非零值,則緊接在 翻譯單位中保留 #if 指示詞後面的行群組。
文法
條件 :
if-part elif-partsopt else-partopt endif-line
if-part :
if-line 文字
if-line :
#if constant-expression
#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
別相同,long
與unsigned int
相同方式。unsigned long
轉譯器可以將字元常數轉譯為一組與目標環境的一組程式碼值不同的程式碼值。 若要判斷目標環境的屬性,請使用針對該環境建置的應用程式來檢查 LIMITS 的值 。H 巨集。
表達式不得查詢環境,而且必須與目標計算機上的實作詳細數據保持隔離。
前置處理器運算子
已定義的
定義的預處理器運算符可用於特殊常數表示式,如下列語法所示:
已定義(識別元)
定義的識別碼
如果標識符目前已定義,這個常數表達式會被視為 true (非零)。 否則,條件為 false (0)。 定義成空白文字的識別項會被視為已定義。 定義的運算子可用於 #if 和 #elif 指示詞,但無處可去。
在下列範例中 ,#if 和 #endif 指示詞會控制三個函數調用之一的編譯:
#if defined(CREDIT)
credit();
#elif defined(DEBIT)
debit();
#else
printerror();
#endif
如果識別項 credit
已定義,就會編譯 CREDIT
的函式呼叫。 如果識別項 DEBIT
已定義,就會編譯 debit
的函式呼叫。 如果這些識別項都未定義,就會編譯 printerror
的呼叫。 CREDIT
和 credit
都是 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