Objective-C中的預(yù)處理器指令與宏

什么是預(yù)處理器,跟我有什么關(guān)系竣稽?

預(yù)處理器是在OC源文件編譯過程中的一個部分囱怕,而且是第一個處理部分,預(yù)處理器的預(yù)也由此可見丧枪。

整個編譯過程可以大致分為:預(yù)處理器進(jìn)行詞法分析 -> 語法分析 -> 生成代碼和優(yōu)化 -> 生成可執(zhí)行的二進(jìn)制文件光涂。

既然有這么多過程,為什么要關(guān)注預(yù)處理器呢拧烦?因?yàn)樗谖覀兊拈_發(fā)中最常見忘闻,而且每個iOS開發(fā)者一定都見過。

不信的話我們可以列舉一下常見的預(yù)處理指令恋博,預(yù)處理器有其區(qū)別于Objective-C的獨(dú)特語法齐佳,語法形式如下:

#指令名 指令參數(shù)

有點(diǎn)眼熟了?我們再具體地說說包含哪些:

  • 頭文件包含(#include债沮、#import)
  • 條件編譯(#if炼吴、#elif、#else疫衩、#endif硅蹦、#ifdef和#ifndef)
  • 診斷(#error、#warning和#line)
  • pragma指令

這樣列出來就明白了吧闷煤,早說是這些就簡單了嘛童芹,大部分都是熟人,慢著鲤拿,這些熟悉的具體表示什么假褪?有什么區(qū)別?那些不太熟的又是干什么的呢近顷?我們一個個來看生音。

除了上述的指令外,還有一個老熟人也屬于預(yù)處理器的范疇窒升,下文再來說缀遍。

預(yù)處理器指令

頭文件包含

學(xué)C語言的時候就接觸到了#include,學(xué)java也會用到import(注意沒有#號)饱须,都是用來導(dǎo)入頭文件的瑟由,這個作用我們明白,OC中的導(dǎo)入頭文件有#include和#import兩種指令,而且對于頭文件名還分為雙引號包含和尖括號包含兩種方式:

#include "頭文件名"

#include <頭文件名>

#import "頭文件名"

#import <頭文件名>

問題來了歹苦,有啥區(qū)別青伤?

先說雙引號和尖括號的區(qū)別,雙引號封裝頭文件名時殴瘦,會先從存儲要編譯的這個文件的目錄中去搜索包含的頭文件狠角,找不到再去用來搜索系統(tǒng)標(biāo)準(zhǔn)頭文件的默認(rèn)目錄搜索。而尖括號封裝頭文件名時蚪腋,會直接去用來搜索系統(tǒng)標(biāo)準(zhǔn)頭文件的默認(rèn)目錄搜索丰歌。由此可見,要用尖括號封裝標(biāo)準(zhǔn)頭文件屉凯,而自己寫的OC類頭文件立帖,應(yīng)該用雙引號封裝。

而對于#include和#import這兩者悠砚,區(qū)別在于#import可以確保頭文件只被引用一次晓勇,這樣就可以防止遞歸包含,什么叫遞歸包含灌旧,A引用B和C绑咱,B也引用了C,那就都包含了C枢泰,這就重復(fù)包含了描融。因此,如果非要用#include衡蚂,那必須額外地寫指令來判斷有沒有包含過窿克,來避免遞歸包含。

條件編譯

條件編譯特別像我們在所有編程語言中都能看到的 if ... else if ... else 形式毛甲,也就是條件判斷語句年叮。

用法如下
#if(對應(yīng)于if)
// 執(zhí)行內(nèi)容
#elif(對應(yīng)于else if)
// 執(zhí)行內(nèi)容
#else(對應(yīng)于else)
// 執(zhí)行內(nèi)容
#endif

對于各個語句的用法要求也和一般語言相同,特殊的是最底下有一個#endif丽啡,畢竟沒有大括號也沒有縮進(jìn)嘛谋右,而且支持嵌套操作硬猫,那嵌套的界限就更要靠#endif來判斷了對吧补箍。

除了這些以外,還有兩個:

#ifdef 宏名
// 執(zhí)行內(nèi)容
#endif

#ifndef 宏名
// 執(zhí)行內(nèi)容
#endif

其中的def是define的簡寫啸蜜,ndef也就是not define坑雅,很容易猜到意思,分別就是判斷是否定義過后面跟著的宏衬横。同樣的要用#endif來作為結(jié)束的界限裹粤。

診斷

診斷中先說頭兩個:

#ifndef 宏名
#error "發(fā)生錯誤啦"
#endif

#if XXX
#warning "警報(bào)!警報(bào)蜂林!"
#endif

一般都用在條件判斷語句內(nèi)容中遥诉,后面都跟著雙引號帶著的消息拇泣,error指令會直接中止編譯,拋出錯誤消息矮锈,warning也會拋出警告消息霉翔,但不會中止編譯。

第三種診斷指令:

#line 行號 "文件名"
//假設(shè)這里有一行會發(fā)生錯誤的代碼

這個指令理解起來有些復(fù)雜苞笨,首先line定義了一個行號债朵,那么之后每一行都會有一個在此基礎(chǔ)上依次加一的行號,比如下一行的錯誤代碼就是第11行瀑凝。發(fā)生錯誤后序芦,會拋出說"文件名"文件的第11行有錯誤。后面跟著的文件名是一個可選項(xiàng)粤咪,寫了就可以在消息中顯示谚中,不寫也沒關(guān)系。

#pragma指令

這個指令更常見了射窒,我們使用UITableView的時候藏杖,經(jīng)常會用到:

#pragma mark - UITableView DataSource
……
#pragma mark - UITableView Delegate
……

這個#pragma mark指令可以在Xcode 中的該文件的方法列表中插入標(biāo)記,#pragma mark -就可以插入一個分隔線脉顿,后跟文字就可以插入文字標(biāo)簽蝌麸。

除此之外,#pragma指令還包含很多別的選項(xiàng)艾疟,上面的是用的最多的来吩,其他的可以查看文檔。

預(yù)處理器之宏

要知道蔽莱,宏也是預(yù)處理器范疇內(nèi)的內(nèi)容弟疆,我們用的也很多:

// 定義常量值
#define 宏名 值
//定義函數(shù)宏
#define 宏名(參數(shù)) 代碼

// 移除宏
#undef 宏名

宏被定義后,會一直存在盗冷,并且能在整個文件中起作用怠苔,直到被#undef指令移除為止。如果函數(shù)有多個參數(shù)仪糖,用逗號分隔開柑司。

定義函數(shù)宏的時候,有一個細(xì)節(jié)要注意锅劝,就是要多對參數(shù)使用括號:

#defind SQUARE(x) ((x) * (x))

為什么要這么麻煩攒驰?為什么不能直接 x * x?要知道故爵,宏在這個意義上是很“傻”的玻粪,它只會單純的將你輸入的x值拿去替換函數(shù)代碼中的x,并不會做什么處理,所以如果你這樣輸入就會造成沒有意料到的結(jié)果:

#defind SQUARE(x) x * x

int number = SQUARE(4+2);// 你以為會等于36劲室?并不會

// 我們說了伦仍,宏只會簡單替換,所以上面等價于:

int number = 4 + 2 * 4 + 2;// 其實(shí)等于14

知道問題所在了吧很洋,這很嚴(yán)重呢铆,因?yàn)椴恢赖脑捀緹o法理解這個bug為什么會出現(xiàn),所以都應(yīng)該使用括號蹲缠。此外棺克,如果你的代碼有多行,還應(yīng)該使用大括號括起來:

#define FUNC(a, b) {a = a + b; b = a - b;}

此外线定,不要過度使用宏娜谊!宏很強(qiáng)大,也很危險斤讥,出了問題往往難以診斷纱皆,也不好維護(hù)。

結(jié)

以上就是OC編譯中的預(yù)處理器中的一些預(yù)處理語言函數(shù)的內(nèi)容芭商,預(yù)處理器的內(nèi)容當(dāng)然不單單只有這些派草,還有對源文件的一些處理,但這些是我們平常開發(fā)中經(jīng)常遇到的铛楣,了解他們是必須且重要的近迁。


查看作者首頁

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市簸州,隨后出現(xiàn)的幾起案子鉴竭,更是在濱河造成了極大的恐慌,老刑警劉巖岸浑,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件搏存,死亡現(xiàn)場離奇詭異,居然都是意外死亡矢洲,警方通過查閱死者的電腦和手機(jī)璧眠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來读虏,“玉大人责静,你說我怎么就攤上這事【蚱” “怎么了泰演?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵呻拌,是天一觀的道長葱轩。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么靴拱? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任垃喊,我火速辦了婚禮,結(jié)果婚禮上袜炕,老公的妹妹穿的比我還像新娘本谜。我一直安慰自己,他們只是感情好偎窘,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布乌助。 她就那樣靜靜地躺著,像睡著了一般陌知。 火紅的嫁衣襯著肌膚如雪他托。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天仆葡,我揣著相機(jī)與錄音赏参,去河邊找鬼。 笑死沿盅,一個胖子當(dāng)著我的面吹牛把篓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播腰涧,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼韧掩,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了窖铡?” 一聲冷哼從身側(cè)響起揍很,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎万伤,沒想到半個月后窒悔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡敌买,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年简珠,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片虹钮。...
    茶點(diǎn)故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡聋庵,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出芙粱,到底是詐尸還是另有隱情祭玉,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布春畔,位于F島的核電站脱货,受9級特大地震影響岛都,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜振峻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一臼疫、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧扣孟,春花似錦烫堤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至利诺,卻和暖如春湾盗,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背立轧。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工格粪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人氛改。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓帐萎,卻偏偏與公主長得像,于是被迫代替她去往敵國和親胜卤。 傳聞我的和親對象是個殘疾皇子疆导,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 目錄 一.預(yù)處理的工作方式... 3 1.1.預(yù)處理的功能... 3 1.2預(yù)處理的工作方式... 3 二.預(yù)處理...
    朱森閱讀 1,355評論 0 2
  • C中的預(yù)編譯宏定義 2009-02-10 作者: infobillows 來源:網(wǎng)絡(luò) 在將一個C源程序轉(zhuǎn)換為可執(zhí)行...
    白水灬煮一切閱讀 1,581評論 0 5
  • 在實(shí)際開發(fā)中,有時候在編譯之前還需要對源文件進(jìn)行簡單的處理葛躏。例如澈段,我們希望自己的程序在Windows和Linux下...
    凡眼觀世界閱讀 850評論 1 0
  • 對你最沉默的時候 是以為你會暗暗關(guān)心 結(jié)果卻是一通氣的發(fā)泄
    小小紙飛機(jī)閱讀 160評論 0 0
  • 即將進(jìn)入耄耋之年、身體也依舊健康的瓊瑤阿姨舰攒,前幾天寫下了“生前遺囑”败富,以公開信的形式,表達(dá)了“尊嚴(yán)死”的意愿摩窃。她甚...
    Runningapple閱讀 336評論 0 0