1. 程式人生 > >C語言條件編譯(#if,#ifdef,#ifndef,#endif,#else,#elif)

C語言條件編譯(#if,#ifdef,#ifndef,#endif,#else,#elif)

1、條件編譯介紹

  • 條件編譯(conditional compiling)命令指定前處理器依據特定的條件來判斷保留或刪除某段原始碼。例如,可以使用條件編譯讓原始碼適用於不同的目標系統,而不需要管理該原始碼的各種不同版本。
  • 條件編譯區域以 #if、#ifdef 或 #ifndef 等命令作為開頭,以 #endif 命令結尾。條件編譯區域可以有任意數量的 #elif 命令,但最多一個 #else 命令。以 #if 開頭的條件編譯區域具有下面的格式:
#if 表示式1
  [ 組1]
[#elif 表示式2
  [ 組2]]
...
[#elif 表示式n
  [ 組n ]]
[#else
  [ 組n+1 ]]
#endif
  • 前處理器會依次計算條件表示式,直到發現結果非 0(也就是 true)的條件表示式。前處理器會保留對應組內的原始碼,以供後續處理。如果找不到值為 true 的表示式,並且該條件式編譯區域中包含 #else 命令,則保留 #else 命令組內的程式碼。
  • 組 1、組 2 等程式碼段,可以包含任意 C 原始碼,也可以包含更多的命令,包括巢狀的條件式編譯命令。在預處理階段結束時,沒有被前處理器保留以用於後續處理的組會從程式中全部刪除。

2、#if 和 #elif 命令

  • 作為 #if 或 #elif 命令條件的表示式,必須是整數常量前處理器表示式。這與普通的整數常量表達式不同,主要區別在於:
    • (1) 不能在 #if 或 #elif 表示式中使用型別轉換運算子。
    • (2) 可以使用預處理運算子 defined。
    • (3) 在前處理器展開所有巨集,並且計算完所有 defined 表示式之後,會使用字元 o 替換掉表示式中所有其他識別符號或關鍵字。
    • (4) 表示式中所有帶符號值都具有 intmax_t 型別,並且所有無符號值都具有 uintmax_t 型別。字元常量也會受該規則的影響。intmax_t 和 uintmax_t 定義在標頭檔案 stdint.h 中。
    • (5) 前處理器會把字元常量和字串字面量中的字元與轉義序列轉換成執行字符集中對應的字元。然而,字元常量在前處理器表示式和在後期編譯階段是否具有相同的值,取決於實現版本。

3、defined 運算子

  • 一元運算子 defined 可以出現在 #if 或 #elif 命令的條件中。它的形式如下:
defined 識別符號
defined (識別符號)
  • 如果指定的 identifier 是一個巨集名稱(也就是說,它已被 #define 命令定義,並且未被 #undef 命令取消定義),則 defined 表示式會生成值 1。否則,defined 表示式會生成值 0。
  • defined 運算子相對於 #ifdef 和 #ifndef 命令的優點是:你可以在更大型的前處理器表示式中使用它的值。如下例所示:
#if defined( __unix__ ) && defined( __GNUC__ )
/* ... */
#endif
  • 大多數編譯器會提供預定義巨集,例如上例所使用的巨集,它用來識別目標系統和編譯器。因此,在 Unix 系統中,通常預先定義好了巨集 __unix__,而 GCC 編譯器則會預先定義好了巨集 __GNUC__。類似地,微軟 Windows 平臺上的 Visual C 編譯器會自動定義好巨集 _WIN32 和巨集 _MSC_VER。

4、#ifdef 和 #ifndef 命令

  • 你可以通過 #ifdef 和 #ifndef 命令測試某個巨集是否已被定義。它們的語法是:
#ifdef 識別符號
#ifndef 識別符號
  • 這等同於下面的 #if 命令:
#if defined 識別符號
#if !defined 識別符號
  • 如果 identifier 不是巨集名稱,則 #ifndef 識別符號後面的條件程式碼被保留。