Objective-C前處理器不是編譯器的一部分,而是編譯過程中的一個單獨步驟。 簡單來說,Objective-C前處理器只是一個文字替換工具,它指示編譯器在實際編譯之前進行必要的預處理。 我們將Objective-C前處理器稱為OCPP。
所有前處理器命令都以井號(#
)開頭。它必須是第一個字元(前面不能有空格),並且為了便於閱讀,前處理器指令應該從第一列開始。 以下部分列出了所有重要的預處理程式指令 -
編號 | 指令 | 描述 |
---|---|---|
1 | #define |
替換前處理器巨集 |
2 | #include |
從另一個檔案插入特定檔頭 |
3 | #undef |
未定義的前處理器巨集 |
4 | #ifdef |
如果定義了此巨集,則返回true |
5 | #ifndef |
如果未定義此巨集,則返回true |
6 | #if |
測試編譯時條件是否為true |
7 | #else |
#if 的替代方案 |
8 | #elif |
在#else 和 #if 中的一個語句 |
9 | #endif |
結束前處理器條件 |
10 | #error |
在stderr 上列印錯誤訊息 |
11 | #pragma |
使用標準化方法向編譯器發出特殊命令 |
分析以下範例以了解各種巨集的指令。
#define MAX_ARRAY_LENGTH 20
該指令告訴OCPP 用20
替換MAX_ARRAY_LENGTH
巨集標識。使用#define
定義常數來提高可讀性。
#import <Foundation/Foundation.h>
#include "myheader.h"
這些指令告訴OCPP 從Foundation Framework獲取foundation.h
,並將文字新增到當前原始檔中。 下一行告訴OCPP 從本地目錄獲取myheader.h
並將內容新增到當前原始檔。
#undef FILE_SIZE
#define FILE_SIZE 42
它告訴OCPP 取消定義現有的FILE_SIZE
,並將FILE_SIZE
定義為42
。
#ifndef MESSAGE
#define MESSAGE "You wish!"
#endif
它告訴OCPP僅在尚未定義MESSAGE
巨集時才定義MESSAGE
。
#ifdef DEBUG
/* Your debugging statements here */
#endif
它告訴OCPP如果定義了DEBUG
,則執行包含語句的過程。 如果在編譯時將- DDEBUG
標誌傳遞給gcc
編譯器,這將非常有用。 它將定義DEBUG
,因此可以在編譯期間動態開啟和關閉偵錯。
ANSI C定義了許多巨集。雖然每個都可用於程式設計,但不應直接修改預定義的巨集。
編號 | 巨集 | 描述 |
---|---|---|
1 | __DATE__ |
當前日期為「MMM DD YYYY」 格式的字元文字 |
2 | __TIME__ |
當前時間作為「HH:MM:SS」 格式的字元文字 |
3 | __FILE__ |
它包含當前檔案名作為字串文字。 |
4 | __LINE__ |
它包含當前行號作為十進位制常數。 |
5 | __STDC__ |
當編譯器符合ANSI標準時,定義為1 。 |
試試下面的例子程式碼 -
#import <Foundation/Foundation.h>
int main() {
NSLog(@"File :%s\n", __FILE__ );
NSLog(@"Date :%s\n", __DATE__ );
NSLog(@"Time :%s\n", __TIME__ );
NSLog(@"Line :%d\n", __LINE__ );
NSLog(@"ANSI :%d\n", __STDC__ );
return 0;
}
當編譯並執行檔案main.m
中的上述程式碼時,它會產生以下結果 -
2018-11-15 08:44:54.041 main[50640] File :main.m
2018-11-15 08:44:54.042 main[50640] Date :Nov 15 2018
2018-11-15 08:44:54.042 main[50640] Time :08:44:52
2018-11-15 08:44:54.042 main[50640] Line :7
2018-11-15 08:44:54.043 main[50640] ANSI :1
Objective-C前處理器提供以下運算子來建立巨集 -
巨集通常必須包含在一行中。巨集延續運算子用於繼續對於單行來說太長的巨集。 例如 -
#define message_for(a, b) \
NSLog(@#a " and " #b ": We love you!\n")
字串化或數位符號運算子(#
)在巨集定義中使用時,將巨集引數轉換為字串常數。 此運算子只能在具有指定引數或引數列表的巨集中使用。 例如 -
#import <Foundation/Foundation.h>
#define message_for(a, b) \
NSLog(@#a " and " #b ": We love you!\n")
int main(void) {
message_for(Carole, Debra);
return 0;
}
執行上面範例程式碼,得到以下結果:
2018-11-15 08:56:38.088 main[98681] Carole and Debra: We love you!
巨集定義中的令牌貼上運算子(##
)組合了兩個引數。 它允許將巨集定義中的兩個單獨的標記連線到一個標記中。 例如 -
#import <Foundation/Foundation.h>
#define tokenpaster(n) NSLog (@"token" #n " = %d", token##n)
int main(void) {
int token34 = 40;
tokenpaster(34);
return 0;
}
執行上面範例程式碼,得到以下結果:
2018-11-15 08:58:04.872 main[138839] token34 = 40
它是如何發生的,因為這個例子導致前處理器的以下實際輸出 -
NSLog (@"token34 = %d", token34);
此範例顯示令牌##n
到token34
的串聯,這裡使用了stringize
和token-pasting
。
前處理器定義的運算子用於常數表示式,以確定是否使用#define
定義識別符號。如果定義了指定的識別符號,則該值為true
(非零)。 如果未定義符號,則值為false
(零)。 定義的運算子指定如下 -
#import <Foundation/Foundation.h>
#if !defined (MESSAGE)
#define MESSAGE "You wish!"
#endif
int main(void) {
NSLog(@"Here is the message: %s\n", MESSAGE);
return 0;
}
執行上面範例程式碼,得到以下結果:
2018-11-15 09:04:30.790 main[31654] Here is the message: You wish!
OCPP的一個強大功能是使用引數化巨集模擬函式的能力。 例如,可能需要一些程式碼來對數位進行平方,如下所示 -
int square(int x) {
return x * x;
}
可以使用巨集重寫上面的程式碼,如下所示 -
#define square(x) ((x) * (x))
必須先使用#define
指令定義帶引數的巨集,然後才能使用它們。 引數列表括在括號中,並且必須緊跟巨集名稱。 巨集名稱和左括號之間不允許有空格。 例如 -
#import <Foundation/Foundation.h>
#define MAX(x,y) ((x) > (y) ? (x) : (y))
int main(void) {
NSLog(@"Max between 20 and 10 is %d\n", MAX(10, 20));
return 0;
}
執行上面範例程式碼,得到以下結果:
2018-11-15 09:08:15.586 main[64146] Max between 20 and 10 is 20