Objective-C預處理器

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 使用標準化方法向編譯器發出特殊命令

1. 預處理器示例

分析以下示例以瞭解各種宏的指令。

#define MAX_ARRAY_LENGTH 20

該指令告訴OCPP20替換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,因此可以在編譯期間動態打開和關閉調試。

2. 預定義的宏

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

3. 預處理器運算符

Objective-C預處理器提供以下運算符來創建宏 -

3.1. 宏延續(\)

宏通常必須包含在一行中。宏延續運算符用於繼續對於單行來說太長的宏。 例如 -

#define  message_for(a, b)  \
   NSLog(@#a " and " #b ": We love you!\n")

3.2. 字串化(#)

字串化或數字符號運算符(#)在宏定義中使用時,將宏參數轉換為字串常量。 此運算符只能在具有指定參數或參數列表的宏中使用。 例如 -

#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!

3.3. 令牌粘貼(##)

宏定義中的令牌粘貼運算符(##)組合了兩個參數。 它允許將宏定義中的兩個單獨的標記連接到一個標記中。 例如 -

#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);

此示例顯示令牌##ntoken34的串聯,這裏使用了stringizetoken-pasting

3.4. defined()運算符

預處理器定義的運算符用於常量運算式,以確定是否使用#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!

4. 參數化宏

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

上一篇: Objective-C結構體 下一篇: Objective-C類型定義(typedef)