通常,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 實現。如下所示:
參考資料:
- Conditional Compilation (#if, #ifdef, #ifndef, #else, #elif, #endif, and defined)
- Using Objective-C Preprocessor Directives
- 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