前言
在一個(gè)xxx.mm文件中膀跌,看到如下類似代碼
#ifdef __cplusplus
extern "C" {
#endif
void printInteger(int count);
#ifdef __cplusplus
}
#endif
預(yù)處理(Preprocess)
源代碼變?yōu)榭蓤?zhí)行文件時(shí)遭商,會(huì)經(jīng)歷四個(gè)過程,預(yù)處理捅伤、編譯劫流、匯編、鏈接丛忆,編譯階段結(jié)束生成匯編代碼祠汇,匯編階段結(jié)束生成可重定位目標(biāo)文件,鏈接階段結(jié)束就生成了可執(zhí)行文件蘸际。那么預(yù)處理階段做了哪些事呢?
-
預(yù)處理階段做的事
1.將頭文件插入源文件中
2.替換宏定義
3.去除注釋
4.條件編譯 include 與import
多說一句題外話徒扶,通過#include 與 #import都可以將頭文件引入源文件中粮彤。但是#import 優(yōu)化了重復(fù)頭文件引入問題,即不會(huì)導(dǎo)致重復(fù)引用,可正常編譯导坟。如下面兩種情況: A屿良,B都引入了C,而D同時(shí)引入了A惫周,B尘惧,則D相同于引入兩次C;A引入了B递递,B引入了C喷橙,而D引入了A,又引入了C登舞。
但是在上述情況下使用 #inculde贰逾,則會(huì)發(fā)生重復(fù)引用的問題 ,編譯會(huì)報(bào)錯(cuò)。
還有循環(huán)依賴的問題菠秒,A引入了B疙剑,B又引入了A,測(cè)試了下Xcode 9.1 對(duì)循環(huán)依賴沒有警告践叠。當(dāng)然業(yè)界多用 @class類引用解除循環(huán)依賴言缤,并且邏輯上看,大部分情況下我們也只需要類文件引用禁灼,并不需要詳細(xì)了解其屬性及接口設(shè)置管挟。
- 總結(jié)
上面基本解釋了#ifdef #endif 是條件編譯,直白翻譯過來就是 如果當(dāng)前文件是 C++源文件匾二,則執(zhí)行extern "C" {}哮独。注意源文件后綴是.mm,表示可使用C++ API察藐。
下面接著說extern "C" {}要做什么皮璧?
extern
我們應(yīng)該經(jīng)常使用extern修飾全局變量,表示該變量可以在其他模塊使用分飞,如:
A.h //聲明
extern int a;
A.m //定義
int a = 1;
B.m
#import <A.h>
//do something with a
- 可以多處聲明悴务,一次賦值,不可以在聲明時(shí)賦值譬猫。
- 聲明的數(shù)據(jù)類型與賦值時(shí)相同
- 未賦值會(huì)報(bào)錯(cuò)讯檐,多次賦值也會(huì)報(bào)錯(cuò)。
extern "C" {block}指明對(duì)待block中的代碼染服,使用類C語言的編譯與鏈接機(jī)制别洪,但語法還是遵循C++的機(jī)制。核心還是C++與類C的混編問題柳刮。
C++與類C混編
我們項(xiàng)目中可能使用Objective-C挖垛,C++兩種語言編寫痒钝,但是不同語言的語法習(xí)慣、編譯和鏈接都是不同的痢毒。
- 注釋掉extern "C"
查看.mm的匯編代碼 送矩,可以看到函數(shù)名是 __Z12printIntergeri,C++中有函數(shù)重載機(jī)制哪替,所以在編譯函數(shù)時(shí)有所不同栋荸。但是在其他類C文件中使用該函數(shù),則會(huì)報(bào)錯(cuò)凭舶,找不到該函數(shù)定義晌块。
- 加入 extern "C"
再次.mm匯編代碼,函數(shù)名則是_printInterger库快,這樣則可以在其他類C文件中使用了摸袁。