Objective-C 預處理器
Objective-C的預處理器是不是編譯器的一部分,但是在編譯過程中是一個單獨的步驟。在簡單的條件,是一個Objective-C預處理器隻是一個文本替換工具,它指示編譯器做實際的編譯之前需要預先處理。我們會參考Objective-C的預處理為OCPP。
井號(#)開頭的所有預處理命令。它必須是第一個非空字符,可讀性,預處理器指令應在第一列開始。下節列出了所有重要的預處理指令:
指示 | 描述 |
---|---|
#define | 替代預處理宏 |
#include | 從另一個文件中插入一個特定的頭 |
#undef | 取消定義預處理宏 |
#ifdef | 如果定義了這個宏返回true |
#ifndef | 返回true,如果該宏冇有被定義 |
#if | 編譯時間條件下的測試,如果是true |
#else | #if 替代方案 |
#elif | #else 和 #if 在一個語句 |
#endif | 結束預處理條件 |
#error | stderr上打印錯誤消息 |
#pragma | 編譯器使用一個標準化的方法發出特殊命令 |
預處理器實例
分析下麵的例子來了解各種指令。
#define MAX_ARRAY_LENGTH 20
該指令告訴OCPP,以取代實例MAX_ARRAY_LENGTH為20。使用#定義常數,以增加可讀性。
#import <Foundation/Foundation.h> #include "myheader.h"
這些的指令告訴OCPP得到 foundation.h 基礎框架和文本添加到當前源文件。下一行告訴 OCPP 從本地目錄得到 myheader.h 的內容添加到當前源文件。
#undef FILE_SIZE #define FILE_SIZE 42
告訴OCPP 取消對現有 FILE_SIZE 的定義,並把它定義為42 。
#ifndef MESSAGE #define MESSAGE "You wish!" #endif
這告訴OCPP定義消息,如果消息冇有被定義。
#ifdef DEBUG /* Your debugging statements here */ #endif
這告訴OCPP如果DEBUG被定義語句隨附過程。如果傳遞 DDEBUG標誌,gcc編譯器在編譯時,這是非常有用的。這將定義DEBUG,所以可以在編譯過程中打開調試和關閉。
預定義宏
ANSI C定義了一些宏。雖然每一個都是供編程使用,預定義宏不應該被直接修改。
Macro | 描述 |
---|---|
__DATE__ | The current date as a character literal in "MMM DD YYYY" format |
__TIME__ | The current time as a character literal in "HH:MM:SS" format |
__FILE__ | This contains the current filename as a string literal. |
__LINE__ | This contains the current line number as a decimal constant. |
__STDC__ | Defined as 1 when the compiler complies with the ANSI standard. |
讓我們試試下麵的例子:
#import <Foundation/Foundation.h> int main() { NSLog(@"File :%s ", __FILE__ ); NSLog(@"Date :%s ", __DATE__ ); NSLog(@"Time :%s ", __TIME__ ); NSLog(@"Line :%d ", __LINE__ ); NSLog(@"ANSI :%d ", __STDC__ ); return 0; }
文件 main.m 上麵的代碼在編譯和執行時,它會產生以下結果:
2013-09-14 04:46:14.859 demo[20683] File :main.m 2013-09-14 04:46:14.859 demo[20683] Date :Sep 14 2013 2013-09-14 04:46:14.859 demo[20683] Time :04:46:14 2013-09-14 04:46:14.859 demo[20683] Line :8 2013-09-14 04:46:14.859 demo[20683] ANSI :1
預處理運算符
Objective-C 預處理器提供了運算符,以幫助創建宏:
宏延續()
宏通常必須包含在一個單一的行。宏延續運算符用於繼續宏的一行。例如:
#define message_for(a, b) NSLog(@#a " and " #b ": We love you! ")
Stringize (#)
stringize或數字符號運算符('#'),在宏定義內使用時,一個宏參數轉換成一個字符串常量。此操作隻可用於在宏具有指定參數或參數列表。例如:
#import <Foundation/Foundation.h> #define message_for(a, b) NSLog(@#a " and " #b ": We love you! ") int main(void) { message_for(Carole, Debra); return 0; }
讓我們編譯和運行上麵的程序,這將產生以下結果:
2013-09-14 05:46:14.859 demo[20683] 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; }
讓我們編譯和運行上麵的程序,這將產生以下結果:
2013-09-14 05:48:14.859 demo[20683] token34 = 40
它是如何發生的,因為這個例子中的結果在下麵從預處理的實際輸出:
NSLog (@"token34 = %d", token34);
這個例子顯示了串聯令牌#n為進token34,這裡我們使用stringize和標記粘貼。
defined() 運算符
預處理器定義的常量表達式運算符用於確定是否使用#define定義一個標識符。如果指定的標識符被定義,該值是真(非零)。如果符號冇有定義,這個值是false(零)。定義的運算符規定如下:
#import <Foundation/Foundation.h> #if !defined (MESSAGE) #define MESSAGE "You wish!" #endif int main(void) { NSLog(@"Here is the message: %s ", MESSAGE); return 0; }
讓我們編譯和運行上麵的程序,這將產生以下結果:
2013-09-14 05:48:19.859 demo[20683] 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 ", MAX(10, 20)); return 0; }
讓我們編譯和運行上麵的程序,這將產生以下結果:
2013-09-14 05:52:15.859 demo[20683] Max between 20 and 10 is 20