條件編譯 Conditional Compilation

通常,Objective-C 程序的編譯從源代碼到可執行文件分爲三個階段。第一階段,預處理程序(preprocessor)的工具掃描開發人員編寫的代碼,並轉換爲對編譯器友好的格式;第二階段,編譯器從預處理的源代碼生成目標代碼(通常文件擴展名爲 .o 格式);最後一個階段,鏈接器(linker)將所有目標代碼模塊和庫放在一起,解析符號鏈接(symbol reference)並創建可執行二進制文件(executable binary)。

預處理階段會搜索開發人員編寫的特殊指令(directive),並將其轉換爲編譯器可以處理的代碼。每個指令均以 # 開頭,用於簡化編程任務,並使代碼易於閱讀和管理。在這篇文章中,將介紹條件編譯(conditional compilation)指令。

六個指令可用於控制條件編譯。條件編譯用於分割僅在滿足指定條件時才編譯指定程序塊,程序塊的文本是任意的,並且可以包含預處理程序指令、C 語句等。這些指令可以嵌套使用。條件編譯的開頭由以下三個指令之一標記:

  • #if
  • #ifdef
  • #ifndef

另外,可選使用下面兩個指令之一來放置備用文本塊:

  • #else
  • #elif

條件編譯的末尾最終由下面命令標記:

  • #endif

如果#if#ifdef#ifndef條件爲真(非0),則忽略#else#elif#endif指令(如果存在)之間的所有行。

如果#if#ifdef#ifndef條件爲假(0),則忽略#if#ifdef#ifndef#else#elif#endif之間的所有行。

#if

#if指令語法如下:

#if constant-expression newline

該指令檢查 constant-expression 是否爲 true,操作數必須是一個整數表達式,不包含增量(++)、減量(--)、sizeof、指針、地址和強制轉換符。

常量表達式中的標誌符可以是宏、也可以不是宏,但不能是關鍵字、枚舉常量等。常量表達式還可以包括已定義的預處理運算符。

#if中的常量表達式實質爲文本替換,並且可以包含之前使用#define指令定義的標誌符。替換髮生在驗證表達式之前,替換之後每個預處理都依照令牌詞彙形式出現。

如果你對#define指令不熟悉,可以查看我的另一篇文章:宏(#define)與常量(const)的使用

如果使用未定義標誌符,則編譯器會將其視爲常量零。

#ifdef

#ifdef指令語法如下:

#ifdef identifier newline

該指令檢查 identifier 是否已定義。可以通過#define命令或命令行定義 identifier,如果該 identifier 稍後未被取消定義(使用#undef命令可以取消已定義的宏),則認爲已定義。

#ifndef

#ifndef指令語法如下:

#ifndef identifier newline

該指令檢查 identifier 是否未定義。

#else

#else指令語法如下:

#else newline

#if#ifdef#ifndef指令驗證爲 false 時,則#else指令界定要編譯的可選文本。#else指令是可選的。

#elif

#elif指令語法如下:

#elif constant-expression newline

#elif指令執行的任務類似於 else if 語句。當#if#ifdef#ifndef爲 false,且#elif爲 true 時,編譯#elif後的代碼。#elif指令是可選的。

#endif

#endif指令語法如下:

#endif newline

#endif指令終止#if#ifdef#ifndef#else#elif指令的範圍。

#endif指令數量根據使用的#elif#else而變化。下面兩個實例等效:

#if false
.
.
#elif true
.
.
#endif

// 等效於

#if false
.
.
#else
#if true
.
.
#endif
#endif

defined 操作符

另一種驗證宏是否已定義的方法是使用defined一元操作符。defined操作符有以下兩種格式:

defined name
defined (name)

如果name已定義,則表達式結果爲1,否則爲0。

defined運算符對於使用#if指令檢查多個宏特別有用。這樣可以在一行檢查多個宏是否定義,而不必使用多個#ifdef#ifndef指令。

#ifdef macro1
    NSLog(@"Hello!\n");
#endif
    
#ifndef macro2
    NSLog(@"Hello!\n");
#endif
    
#ifdef macro3
    NSLog(@"Hello!\n");
#endif

使用defined運算符則可以在單個#if指令中執行類似宏檢查:

#if defined (macro1) || !defined (macro2) || defined (macro3)
    print("Hello!\n")
#endif

defined指令可以和任意邏輯運算符組合使用,但defined指令只能用在#if#elif指令的表達式中。

#import也是預處理指令。

如果一個 project 包含多個 target,想要通過預處理程序進行區分,則可以選中 target,修改 Build Settings 中 Preprocessing Macros 實現。如下所示:

參考資料:

  1. Conditional Compilation (#if, #ifdef, #ifndef, #else, #elif, #endif, and defined)
  2. Using Objective-C Preprocessor Directives
  3. How can I add an #ifdef DEBUG to Xcode?

歡迎更多指正:https://github.com/pro648/tips/wiki

本文地址:https://github.com/pro648/tips/wiki/%E6%9D%A1%E4%BB%B6%E7%BC%96%E8%AF%91-Conditional-Compilation

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章