iOS預編譯指令詳解

1.預處理的概念

ANSI C標準(ANSI C是美國國家標準協會(ANSI)對C語言發布的標準)規定可以在C源程序中加入一些“預處理命令” ,以改進程序設計環境,提高編程效率。這些預處理命令是由ANSI C統一規定的,但是它不是C語言本身的組成部分,不能直接對它們進行編譯,因為編譯程序不能識別它們,必須在對程序進行通常的編譯之前,先對程序中這些特殊的命令進行處理,這一過程就是我們說的“預處理”。經過預處理后程序可由編譯程序對預處理后的源程序進行通常的編譯,得到可供執行的目標代碼。

2.預處理指令功能

在C語言中包括三類預處理指令:1.宏定義 2.條件編譯 3.文件包含。

宏定義:

(1)宏的定義

定義格式: #define 標識符 字符串
1、 不含參數: #define TAG_VIEW 10086
2、 含有參數:#define MAX_INT(a,b) a+b

(2)宏定義的說明

1、宏名一般習慣用大寫字母表示,以便與變量名相區別。但這并非規定,也可用小寫字母。
2、 宏定義是用宏名代替一個字符串,只作簡單置換,不作正確性檢查,同時也不會做運算邏輯處理,同時在進行宏定義時,可以引用已定義的宏名,可以層層置換。(在這里需要特別注意的是:當宏涉運算時,要根據情況來添加括號,防止運算邏輯出現錯誤,如下圖所示,當你宏MAX_TXT想作為整體來使用時應該寫成這樣: #define MAX_INT (2+3) 這樣MAX_END的結果應該是25,如果不加括號,只會進行置換行為,MAX_END的結果就為11。在這非常感謝 @星星月亮落一地 的提醒)


3、 宏定義不是C語句,不必在行末加分號。如果加了分號則會連分號一起進行置換。
4、 #define 命令出現在程序中函數的外面,宏名的有效范圍為定義命令之后到本文件結束。通常,#define 命令寫在文件開頭,函數之前,作為文件一部分,在此文件范圍內有效。
5、 可以用
#undef
命令終止宏定義的作用域。

6、對程序中用雙撇號括起來的字符串內的字符,即使與宏名相同,也不進行置換。NSLog(@"MAX_INT = %d", 10086)
7、宏定義是專門用于預處理命令的一個專用名詞,它與定義變量的含義不同,只作字符替換,不分配內存空間。

條件編譯:

條件編譯就是在編譯之前預處理器根據預處理指令判斷對應的條件,如果條件滿足就將對應的代碼編譯進去,否則代碼就根本不進入編譯環節(相當于根本就沒有這段代碼)。

常用條件編譯函數

1、#if 編譯預處理中的條件命令, 相當于C語法中的if語句
2、#ifdef 判斷某個宏是否被定義, 若已定義, 執行隨后的語句
3、#ifndef 與#ifdef相反, 判斷某個宏是否未被定義
4、#elif 若#if, #ifdef, #ifndef或前面的#elif條件不滿足, 則執行#elif之后的語句, 相當于C語法中的else-if
6、#else 與#if, #ifdef, #ifndef對應, 若這些條件不滿足, 則執行#else之后的語句, 相當于C語法中的else
7、#endif #if, #ifdef, #ifndef這些條件命令的結束標志.
8、#if 與 #ifdef 的區別:#if是判斷后面的條件語句是否成立,#ifdef是判斷某個宏是否被定義過。要區分開!

#ifdef  MAX_F
// 如果定義了宏MAX_F,則編譯此處的代碼
#else
// 如果沒有定義宏MAX_F,則編譯此處的代碼
#endif

// 同樣
#ifndef  MAX_F
// 如果沒有定義宏MAX_F,則編譯此處的代碼
#elif MAX_INT
// 如果定義了宏MAX_F,同時還定義了宏MAX_INT,則編譯此處的代碼
#else
// 定義了宏MAX_F,但是沒有定義宏MAX_INT,則編譯此處的代碼
#endif

另外,在創建一個頭文件或pch文件 --- 單獨的一個.h文件時,??吹轿募茸詭Я讼率龈袷絻热?/p>

#ifndef Header_h 
#define Header_h 

#endif

上面的格式是為了防止該頭文件被引用時發生重復引用。

文件包含:

C語言下一般使用 #include, OC中一般使用#import ,它們的區別是:在使用#include的時候要注意處理重復引用,#import大部分功能和#include是一樣的,但是他處理了重復引用的問題,我們在引用文件的時候不用再去自己進行重復引用處理。OC中還有一個引用聲明 @class主要是用于聲明一個類,告訴編譯器它后面的名字是一個類的名字,而這個類的定義實現是暫時不用知道的。一般來說,在interface中(.h文件)引用一個類,就用@class,它會把這個類作為一個類型來使用,而在實現這個interface的文件中,如果需要引用這個類的實體變量或者方法之類的,還是需要import這個在@class中聲明的類。

3.關于宏的靈活使用和拓展:

1、在宏中拼接新的宏(限字符串)

(1)OC的代碼寫法:

#define aaa @"i am aaa"
#define bbb @"i am bbb"
#define  ccc @""bbb@" "aaa@""

打印ccc的結果如下


(2)C的寫法

#define aaa "i am aaa"
#define bbb "i am bbb"
#define  ccc ""bbb" "aaa""

打印結果是一樣的。

2、預處理連接符:#操作符的字符串化和 ##操作符

(1)在含參數宏中,假如希望在字符串中包含宏的參數本身,#符號用作一個預處理運算符,它可以把語言符號轉化成字符串該過程稱為字符串化(stringizing)。

//定義含參宏
#define MAX_TAG(maxTag) NSLog(@"the max tag "#maxTag" %d", maxTag *3)
-----------------------------------------------------------------------
// 調用
 MAX_TAG(33);
-----------------------------------------------------------------------
//打印結果為
2016-11-29 10:53:45.655 SpeachTest[2294:271425] the max tag 33 99

(2)# #操作符結合了兩種標記成一個token,該標記可以替代部分字符串。

 #define MMM(a)   a ## Button
--------------------------------------------------------------------
    NSString * MMM(title) = @"asd";
    NSLog(@"titleButton = %@",MMM(title));
    NSLog(@"titleButton = %@", titleButton);
--------------------------------------------------------------------
//打印的結果
2016-11-29 10:57:27.364 SpeachTest[2179:233773] titleButton = asd
2016-11-29 10:57:27.367 SpeachTest[2179:233773] titleButton = asd

在這里我并沒有直接定義“titleButton”,但是打印titleButton不但不報錯而且titleButton已經定義過了。 titleButton其實就是MMM(title),這就是##的作用,大家可以試一下。

3、在宏定義中換行

只需要在每行的結尾添加反斜杠“\”

#define SHOWALERT(m)\
{\
    UIAlertView *alert  =  [[UIAlertView alloc]  initWithTitle:@" 提 示 "  message:m delegate:nil cancelButtonTitle:@"確認" otherButtonTitles:nil];\
    [alert show];\
}\

4、 defined()函數 與 #if等條件條件編譯函數的應用

#define aaa "i am aaa"
#if ( defined(aaa) && !defined(bbb) )
#define bbb "i am bbb"
#else
#define bbb "i am bbb_2"
#endif

打印bbb的結果:


5、 省略號···和 VA_ARGS

關于省略號··· 代表的是個數可變的參數即可變參數,一般會與__VA__ARGS__結合使用,__VA__ARGS__表示保留名,將省略號省略的參數傳遞給宏。

// 例如我們最常見的形式
#ifdef DEBUG
#define JRLog(...) NSLog(__VA_ARGS__)
#else
#define JRLog(...)// 如果編譯經過在這里那么JRLog(···)無意義
#endif

還有當含參數宏的參數至少有一個時:

#ifdef DEBUG
#define JRLog(aaa, ...) NSLog(aaa, ##__VA_ARGS__)
#else
#define JRLog(...)
#endif

此時##的作用是在可變參數被忽略或為空的情況下,‘##’操作將使預處理器去除掉“···”前面的那個逗號。

  • 特別注意:省略號···只能出現在參數的最后面,放在其他參數中間或者前面是不可以的!

6、iOS常用的系統內參數宏

// 判斷是否是真機
#if TARGET_OS_IPHONE // 在這里一定不能使用#ifdef,因為TARGET_OS_IPHONE無論在真機還是模擬器情況下都存在只不過 模擬器時值為0
#else
#endif
// 判斷是否是模擬器
#if TARGET_OS_SIMULATOR // 同上。"TARGET_IPHONE_SIMULATOR"已經廢棄
#else
#endif
// 判斷手機系統版本
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0
#else
#endif
// 規定只能在ios系統下運行
#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED 
    // 規定運行支持的最小版本
    #if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0
    #else
    #endif
#endif
// 可以參照Availability.h 文件  文件路徑 /Applications/Xcode8.1.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include 不同Xcode版本路徑略有差異
/**
 #define __IPHONE_2_0      20000
 #define __IPHONE_2_1      20100
 #define __IPHONE_2_2      20200
 #define __IPHONE_3_0      30000
 #define __IPHONE_3_1      30100
 #define __IPHONE_3_2      30200
 #define __IPHONE_4_0      40000
 #define __IPHONE_4_1      40100
 #define __IPHONE_4_2      40200
 #define __IPHONE_4_3      40300
 #define __IPHONE_5_0      50000
 #define __IPHONE_5_1      50100
 #define __IPHONE_6_0      60000
 #define __IPHONE_6_1      60100
 #define __IPHONE_7_0      70000
 #define __IPHONE_7_1      70100
 #define __IPHONE_8_0      80000
 #define __IPHONE_8_1      80100
 #define __IPHONE_8_2      80200
 #define __IPHONE_8_3      80300
 #define __IPHONE_8_4      80400
 #define __IPHONE_9_0      90000
 #define __IPHONE_9_1      90100
 #define __IPHONE_9_2      90200
 #define __IPHONE_9_3      90300
 #define __IPHONE_10_0    100000
 #define __IPHONE_10_1    100100
 */

開發常用的一些宏定義網上有很多,這里就不一一列舉了,希望對讀者有幫助。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 目錄 一.預處理的工作方式... 3 1.1.預處理的功能... 3 1.2預處理的工作方式... 3 二.預處理...
    朱森閱讀 1,409評論 0 2
  • C中的預編譯宏定義 2009-02-10 作者: infobillows 來源:網絡 在將一個C源程序轉換為可執行...
    白水灬煮一切閱讀 1,640評論 0 5
  • 在源代碼的編譯過程中,會需要一些機制來完成以下的一些功能:在編譯時包含其他源文件、定義宏、根據條件決定編譯時是否包...
    趙亦晨閱讀 583評論 0 0
  • 文/孤鳥差魚 不要東拉西扯 別折磨打吊瓶的人
    孤鳥差魚閱讀 182評論 0 2
  • 今天你是否會想起,昨天學醫的你;明天你是否會惦記,這個溫暖的群體!二十年之后的同學,都已改變模樣;雖然有各自的事業...
    關中刀客閱讀 236評論 0 0