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
*/
開發常用的一些宏定義網上有很多,這里就不一一列舉了,希望對讀者有幫助。