1.預(yù)處理的概念
ANSI C標(biāo)準(zhǔn)(ANSI C是美國國家標(biāo)準(zhǔn)協(xié)會(ANSI)對C語言發(fā)布的標(biāo)準(zhǔn))規(guī)定可以在C源程序中加入一些“預(yù)處理命令” ,以改進(jìn)程序設(shè)計(jì)環(huán)境藤树,提高編程效率。這些預(yù)處理命令是由ANSI C統(tǒng)一規(guī)定的,但是它不是C語言本身的組成部分闻妓,不能直接對它們進(jìn)行編譯,因?yàn)榫幾g程序不能識別它們掠械,必須在對程序進(jìn)行通常的編譯之前由缆,先對程序中這些特殊的命令進(jìn)行處理,這一過程就是我們說的“預(yù)處理”猾蒂。經(jīng)過預(yù)處理后程序可由編譯程序?qū)︻A(yù)處理后的源程序進(jìn)行通常的編譯均唉,得到可供執(zhí)行的目標(biāo)代碼。
2.預(yù)處理指令功能
在C語言中包括三類預(yù)處理指令:1.宏定義 2.條件編譯 3.文件包含婚夫。
宏定義:
(1)宏的定義
定義格式: #define 標(biāo)識符 字符串
1浸卦、 不含參數(shù): #define TAG_VIEW 10086
2、 含有參數(shù):#define MAX_INT(a,b) a+b
(2)宏定義的說明
1案糙、宏名一般習(xí)慣用大寫字母表示限嫌,以便與變量名相區(qū)別。但這并非規(guī)定时捌,也可用小寫字母怒医。
2、 宏定義是用宏名代替一個(gè)字符串奢讨,只作簡單置換稚叹,不作正確性檢查,同時(shí)也不會做運(yùn)算邏輯處理,同時(shí)在進(jìn)行宏定義時(shí)拿诸,可以引用已定義的宏名扒袖,可以層層置換。(在這里需要特別注意的是:當(dāng)宏涉運(yùn)算時(shí)亩码,要根據(jù)情況來添加括號季率,防止運(yùn)算邏輯出現(xiàn)錯(cuò)誤,如下圖所示描沟,當(dāng)你宏MAX_TXT想作為整體來使用時(shí)應(yīng)該寫成這樣: #define MAX_INT (2+3)
這樣MAX_END的結(jié)果應(yīng)該是25飒泻,如果不加括號,只會進(jìn)行置換行為吏廉,MAX_END的結(jié)果就為11泞遗。在這非常感謝 @星星月亮落一地 的提醒)
3、 宏定義不是C語句席覆,不必在行末加分號史辙。如果加了分號則會連分號一起進(jìn)行置換。
4、 #define 命令出現(xiàn)在程序中函數(shù)的外面髓霞,宏名的有效范圍為定義命令之后到本文件結(jié)束卦睹。通常,#define 命令寫在文件開頭方库,函數(shù)之前结序,作為文件一部分,在此文件范圍內(nèi)有效纵潦。
5徐鹤、 可以用#undef 命令終止宏定義的作用域。
6邀层、對程序中用雙撇號括起來的字符串內(nèi)的字符返敬,即使與宏名相同,也不進(jìn)行置換寥院。
NSLog(@"MAX_INT = %d", 10086)
7劲赠、宏定義是專門用于預(yù)處理命令的一個(gè)專用名詞,它與定義變量的含義不同秸谢,只作字符替換凛澎,不分配內(nèi)存空間。
條件編譯:
條件編譯就是在編譯之前預(yù)處理器根據(jù)預(yù)處理指令判斷對應(yīng)的條件估蹄,如果條件滿足就將對應(yīng)的代碼編譯進(jìn)去塑煎,否則代碼就根本不進(jìn)入編譯環(huán)節(jié)(相當(dāng)于根本就沒有這段代碼)。
常用條件編譯函數(shù)
1臭蚁、#if 編譯預(yù)處理中的條件命令, 相當(dāng)于C語法中的if語句
2最铁、#ifdef 判斷某個(gè)宏是否被定義, 若已定義, 執(zhí)行隨后的語句
3、#ifndef 與#ifdef相反, 判斷某個(gè)宏是否未被定義
4垮兑、#elif 若#if, #ifdef, #ifndef或前面的#elif條件不滿足, 則執(zhí)行#elif之后的語句, 相當(dāng)于C語法中的else-if
6冷尉、#else 與#if, #ifdef, #ifndef對應(yīng), 若這些條件不滿足, 則執(zhí)行#else之后的語句, 相當(dāng)于C語法中的else
7、#endif #if, #ifdef, #ifndef這些條件命令的結(jié)束標(biāo)志.
8系枪、#if 與 #ifdef 的區(qū)別:#if是判斷后面的條件語句是否成立网严,#ifdef是判斷某個(gè)宏是否被定義過。要區(qū)分開嗤无!
#ifdef MAX_F
// 如果定義了宏MAX_F,則編譯此處的代碼
#else
// 如果沒有定義宏MAX_F怜庸,則編譯此處的代碼
#endif
// 同樣
#ifndef MAX_F
// 如果沒有定義宏MAX_F当犯,則編譯此處的代碼
#elif MAX_INT
// 如果定義了宏MAX_F,同時(shí)還定義了宏MAX_INT,則編譯此處的代碼
#else
// 定義了宏MAX_F,但是沒有定義宏MAX_INT割疾,則編譯此處的代碼
#endif
另外,在創(chuàng)建一個(gè)頭文件或pch文件 --- 單獨(dú)的一個(gè).h文件時(shí)嚎卫,常看到文件內(nèi)自帶了下述格式內(nèi)容
#ifndef Header_h
#define Header_h
#endif
上面的格式是為了防止該頭文件被引用時(shí)發(fā)生重復(fù)引用。
文件包含:
C語言下一般使用 #include, OC中一般使用#import ,它們的區(qū)別是:在使用#include的時(shí)候要注意處理重復(fù)引用拓诸,#import大部分功能和#include是一樣的,但是他處理了重復(fù)引用的問題,我們在引用文件的時(shí)候不用再去自己進(jìn)行重復(fù)引用處理侵佃。OC中還有一個(gè)引用聲明 @class主要是用于聲明一個(gè)類,告訴編譯器它后面的名字是一個(gè)類的名字,而這個(gè)類的定義實(shí)現(xiàn)是暫時(shí)不用知道的。一般來說,在interface中(.h文件)引用一個(gè)類,就用@class,它會把這個(gè)類作為一個(gè)類型來使用,而在實(shí)現(xiàn)這個(gè)interface的文件中,如果需要引用這個(gè)類的實(shí)體變量或者方法之類的,還是需要import這個(gè)在@class中聲明的類奠支。
3.關(guān)于宏的靈活使用和拓展:
1馋辈、在宏中拼接新的宏(限字符串)
(1)OC的代碼寫法:
#define aaa @"i am aaa"
#define bbb @"i am bbb"
#define ccc @""bbb@" "aaa@""
打印ccc的結(jié)果如下
(2)C的寫法
#define aaa "i am aaa"
#define bbb "i am bbb"
#define ccc ""bbb" "aaa""
打印結(jié)果是一樣的。
2倍谜、預(yù)處理連接符:#操作符的字符串化和 ##操作符
(1)在含參數(shù)宏中迈螟,假如希望在字符串中包含宏的參數(shù)本身,#符號用作一個(gè)預(yù)處理運(yùn)算符尔崔,它可以把語言符號轉(zhuǎn)化成字符串該過程稱為字符串化(stringizing)答毫。
//定義含參宏
#define MAX_TAG(maxTag) NSLog(@"the max tag "#maxTag" %d", maxTag *3)
-----------------------------------------------------------------------
// 調(diào)用
MAX_TAG(33);
-----------------------------------------------------------------------
//打印結(jié)果為
2016-11-29 10:53:45.655 SpeachTest[2294:271425] the max tag 33 99
(2)# #操作符結(jié)合了兩種標(biāo)記成一個(gè)token,該標(biāo)記可以替代部分字符串。
#define MMM(a) a ## Button
--------------------------------------------------------------------
NSString * MMM(title) = @"asd";
NSLog(@"titleButton = %@",MMM(title));
NSLog(@"titleButton = %@", titleButton);
--------------------------------------------------------------------
//打印的結(jié)果
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不但不報(bào)錯(cuò)而且titleButton已經(jīng)定義過了洗搂。 titleButton其實(shí)就是MMM(title),這就是##的作用载弄,大家可以試一下耘拇。
3、在宏定義中換行
只需要在每行的結(jié)尾添加反斜杠“\”
#define SHOWALERT(m)\
{\
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@" 提 示 " message:m delegate:nil cancelButtonTitle:@"確認(rèn)" otherButtonTitles:nil];\
[alert show];\
}\
4侦锯、 defined()函數(shù) 與 #if等條件條件編譯函數(shù)的應(yīng)用
#define aaa "i am aaa"
#if ( defined(aaa) && !defined(bbb) )
#define bbb "i am bbb"
#else
#define bbb "i am bbb_2"
#endif
打印bbb的結(jié)果:
5驼鞭、 省略號···和 VA_ARGS
關(guān)于省略號··· 代表的是個(gè)數(shù)可變的參數(shù)即可變參數(shù),一般會與__VA__ARGS__
結(jié)合使用尺碰,__VA__ARGS__
表示保留名挣棕,將省略號省略的參數(shù)傳遞給宏。
// 例如我們最常見的形式
#ifdef DEBUG
#define JRLog(...) NSLog(__VA_ARGS__)
#else
#define JRLog(...)// 如果編譯經(jīng)過在這里那么JRLog(···)無意義
#endif
還有當(dāng)含參數(shù)宏的參數(shù)至少有一個(gè)時(shí):
#ifdef DEBUG
#define JRLog(aaa, ...) NSLog(aaa, ##__VA_ARGS__)
#else
#define JRLog(...)
#endif
此時(shí)##的作用是在可變參數(shù)被忽略或?yàn)榭盏那闆r下亲桥,‘##’操作將使預(yù)處理器去除掉“···”前面的那個(gè)逗號洛心。
- 特別注意:省略號···只能出現(xiàn)在參數(shù)的最后面,放在其他參數(shù)中間或者前面是不可以的题篷!
6词身、iOS常用的系統(tǒng)內(nèi)參數(shù)宏
// 判斷是否是真機(jī)
#if TARGET_OS_IPHONE // 在這里一定不能使用#ifdef,因?yàn)門ARGET_OS_IPHONE無論在真機(jī)還是模擬器情況下都存在只不過 模擬器時(shí)值為0
#else
#endif
// 判斷是否是模擬器
#if TARGET_OS_SIMULATOR // 同上番枚。"TARGET_IPHONE_SIMULATOR"已經(jīng)廢棄
#else
#endif
// 判斷手機(jī)系統(tǒng)版本
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0
#else
#endif
// 規(guī)定只能在ios系統(tǒng)下運(yùn)行
#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
// 規(guī)定運(yùn)行支持的最小版本
#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
*/
開發(fā)常用的一些宏定義網(wǎng)上有很多法严,這里就不一一列舉了,希望對讀者有幫助葫笼。