淺談C/C++混合編程

****如只想知道怎樣就能實(shí)現(xiàn)C/C++混合編程而不深究為什么的話, 可以一拉到底直接看總結(jié).****

首先, 在介紹C/C++混合編程之前, 先思考幾個(gè)問題

1. C/C++混合編程是什么?

2. C/C++混合編程有什么用?

3. C/C++混合編程應(yīng)該怎么實(shí)現(xiàn)?

下面, 簡(jiǎn)單講講我對(duì)C/C++混合編程的理解 :?


1. C/C++混合編程是什么?

就像問題本身所說, C/C++混合編程也就是一個(gè)工程中, 在C函數(shù)中調(diào)用C++函數(shù)的方法, 在C++的函數(shù)中能夠調(diào)用C函數(shù)的方法.


2. C/C++混合編程有什么用?

在我們?nèi)粘i_發(fā)中, 也許會(huì)遇到這么一些情況, 同事A, C非常牛逼, 但是對(duì)C++一竅不通; 同事B, C++信手拈來, 但是對(duì)C卻滿頭霧水. 但是在工作中有這么一種需求, 同事A需要用到C++的方法, 同事B需要用到C的方法,? 這怎么辦??

沒錯(cuò), 最簡(jiǎn)單的就是, 同事A把C的代碼寫好, 然后同事B只管調(diào)用即可, 同理, 同事A只管調(diào)用同事B寫好的C++代碼, 各司其職, 提高工作效率.?


3. C/C++混合編程應(yīng)該怎么實(shí)現(xiàn)?

那么, 這混合編程究竟要怎么實(shí)現(xiàn)呢?

在介紹之前, 我們先簡(jiǎn)單了解下以下幾個(gè)概念

1. 函數(shù)重載

2. C++的名字改編機(jī)制

3. extern 及 extern "C"

* 函數(shù)重載(Overloading)

C++和Java中的函數(shù)重載的定義一致,?

即在相同的作用域內(nèi), C++允許多個(gè)函數(shù)名稱相同, 而形參列表不同, 如下圖所示 :?

函數(shù)重載

然而大家有沒有想過為什么C++支持函數(shù)重載, 而C卻不支持函數(shù)重載呢??

這個(gè)就要涉及到C++的名字改編機(jī)制了. 請(qǐng)往下看~


* C++的名字改編機(jī)制

在C中,?

void test(); // 該函數(shù)編譯后編譯器會(huì)對(duì)函數(shù)名稱改寫成 _test?


C語(yǔ)言中的test()函數(shù)


C語(yǔ)言編譯器改名后的test()函數(shù)叫_test

ps: 不提供test()函數(shù)的實(shí)現(xiàn)是讓Xcode鏈接的時(shí)候報(bào)錯(cuò), 這樣我們才能看清楚test()函數(shù)的真面目!

void test(int a); // 該函數(shù)編譯后編譯器改寫函數(shù)名后依然是 _test


C語(yǔ)言中的test(int)函數(shù)


C語(yǔ)言編譯器改名后的test(int)函數(shù)依舊叫_test

在C++中,?

void test(); // 該函數(shù)編譯后編譯器會(huì)對(duì)函數(shù)名稱改寫成 test()


C++編譯器改名后的test()函數(shù)叫test()

void test(int a); // 該函數(shù)編譯后編譯器改寫函數(shù)名后是 test(int)


C++編譯器改名后的test(int)函數(shù)叫test(int)

ps : 有的系統(tǒng)的編譯器會(huì)編譯成 _test_int 這種格式, 名字改編機(jī)制只是一種思路, 并沒有一種唯一的命名規(guī)范, 不同的編譯器命名規(guī)范不同, 但是思路一致! 如下圖所示 :?


編譯器不同所產(chǎn)生的函數(shù)名可能不同

本文就舉這幾個(gè)例子, 大家可以自行嘗試重載多幾個(gè)函數(shù), 然后動(dòng)手試試看結(jié)果. 實(shí)踐才是王道!

通過上面幾個(gè)例子, 相信大家很容易就能知道為什么C++支持重載而C不支持重載了.

因?yàn)镃++有名字改編機(jī)制而C沒有!

所以在C中, 只要函數(shù)名相同, 不管你的形參列表如何南轅北轍, 編譯器均會(huì)將其編譯為同一函數(shù)名, 這樣在程序執(zhí)行過程中就會(huì)造成函數(shù)調(diào)用的二義性(也就是對(duì)于相同函數(shù)名的函數(shù), 程序并不知道應(yīng)該調(diào)用哪一個(gè)函數(shù)), 這是不允許的, 所以會(huì)報(bào)錯(cuò).?

然而對(duì)于C++而言, 盡管他們的函數(shù)名相同, 但是因?yàn)樗麄兊男螀⒘斜聿煌? 編譯器編譯后實(shí)際上會(huì)為他們改名為不同名字的函數(shù), 所以程序執(zhí)行調(diào)用函數(shù)的時(shí)候并不會(huì)產(chǎn)生二義性, 因此C++允許函數(shù)重載.?

這里扯一句題外話, C++的重載被認(rèn)為不是多態(tài), 因?yàn)槎鄳B(tài)是動(dòng)態(tài)運(yùn)行時(shí)對(duì)方法的綁定, 而C++的函數(shù)重載最多算是編譯時(shí)的"多態(tài)". (這句話不一定正確, 請(qǐng)大家糾正)


*?extern 及 extern "C"

extern相信大家比較熟悉, 它一般用來聲明一個(gè)函數(shù), 全局變量的作用域. extern告訴編譯器, 其聲明的函數(shù)和變量可以供本文件或者其他文件使用. 這里不再贅述.?

extern "C" 中的C是什么意思呢?

這里的C不是指C語(yǔ)言這一門語(yǔ)言, 而是表示一種編譯和鏈接的規(guī)約. C表示符合C語(yǔ)言的編譯和連接規(guī)約的任何語(yǔ)言脱衙,如Fortran(公式翻譯)轮傍、assembler(匯編語(yǔ)言)等。

注意 :?

extern "C" 只是指定編譯和鏈接的規(guī)約, 并不會(huì)影響語(yǔ)義, 所以在C++文件中該怎么寫還得怎么寫, 必須遵循C++的語(yǔ)法規(guī)范.?

在C++源文件的語(yǔ)句前加上 extern "C" 的作用就是告訴編譯器, 這一段代碼按照類C的編譯和鏈接規(guī)約來編譯和鏈接(對(duì), 也就是按照類C的函數(shù)命名規(guī)范編譯)

小技巧 : 如果有多條語(yǔ)句需要extern "C", 可以用{ } 括住, 例如 :

extern "C" 用法

那應(yīng)該怎樣使用extern "C" 來 實(shí)現(xiàn)C/C++混合編程呢?

1. C中調(diào)用C++的代碼

2. C++中調(diào)用C的代碼

3. C/C++互調(diào)


* C中調(diào)用C++的代碼

廢話不多說, 上代碼.?


C調(diào)用C++中定義的sum(int, int)函數(shù)

毫無(wú)疑問, 這段代碼是鏈接不通過的, 為什么呢?

在C中, 編譯器會(huì)將main函數(shù)中調(diào)用的sum函數(shù)編譯為_sum, 然而遠(yuǎn)在那邊寫在C++文件中的sum函數(shù)則被編譯為sum(int, int), 則鏈接的時(shí)候編譯器會(huì)報(bào)找不到_sum函數(shù)的錯(cuò)誤. 如下圖


未定義的_sum函數(shù)

解決思路很明確, 只要確保函數(shù)在C和C++文件中編譯鏈接的規(guī)約一樣就OK了!

這時(shí)候extern "C" 就要閃亮登場(chǎng)了!

此時(shí)我們只需要在cpp文件中用extern "C" { } 把需要被C文件調(diào)用的函數(shù)包含即可, 如下圖

編譯成功, 輸出結(jié)果正確

* C++中調(diào)用C的代碼


C++調(diào)用C的sum(int, int)函數(shù)
同樣, 因?yàn)榫幾g鏈接函數(shù)命名規(guī)范不同導(dǎo)致找不到函數(shù)

此時(shí), 我們不能像之前C調(diào)用C++的方法來解決問題, 原因是 extern "C" 并不能在C文件中使用, 況且C文件本來就遵循C的編譯和鏈接規(guī)約, 就算能在.c文件中使用extern "C" 也無(wú)濟(jì)于事.?

此時(shí)就涉及到#include的作用了, 眾所周知, #include相當(dāng)于文本拷貝, 等于把在頭文件中聲明的C函數(shù)原封不動(dòng)cpy到#include "zs.h"中, 如下圖

#include

有的朋友可能就想到了, 既然函數(shù)聲明已經(jīng)被copy到了C++文件中, 只需要保證C++文件中的這段函數(shù)聲明代碼按照類C的編譯, 鏈接規(guī)約進(jìn)行編譯和鏈接就能保證編譯出的sum函數(shù)的名稱與C文件中的函數(shù)名稱保持一致了!

所以便有了以下方法

Done!

細(xì)心的朋友就會(huì)發(fā)現(xiàn), 既然#include相當(dāng)于文本拷貝, 那為何不把extern "C" 語(yǔ)句放到頭文件中呢?

好的, 我們?cè)囋噡

果不其然, 運(yùn)行成功

但是我很遺憾的告訴大家, 如果你這樣做的話, 那么C文件就不能調(diào)用C文件的方法了!

因?yàn)镃的編譯器不支持 extern "C" 語(yǔ)法!

這里要引出一個(gè)宏, __cplusplus, 只要是C++文件, 編譯器就會(huì)自動(dòng)定義一個(gè)這樣的宏, 我們就能利用這個(gè)宏做到C/C++的終極混編了!

C調(diào)用C函數(shù)成功
C++調(diào)用C函數(shù)成功

總結(jié)

要想寫一套C/C++均能調(diào)用的函數(shù), 則必須按照C的方式編譯 (因?yàn)镃語(yǔ)言不支持C++, 而C++同時(shí)支持C/C++)

要實(shí)現(xiàn)C/C++混合編程其實(shí)很簡(jiǎn)單, 只需要在頭文件加幾行代碼即可, 如下圖

C/C++混合編程核心代碼

有趣的是, Objective-C的函數(shù)編譯命名規(guī)范與C語(yǔ)言一樣, 由此可知如果要實(shí)現(xiàn)C/OC/C++混合編程, 跟C/C++編程是大同小異.


人生第一篇文章, 如果您耐心看完了, 非常感謝您的支持! 如有不對(duì)的地方, 非常歡迎大家指出錯(cuò)誤.


歡迎大家關(guān)注@Jerry4me, 關(guān)注菜鳥成長(zhǎng)^_^. 我會(huì)不定時(shí)更新一些學(xué)習(xí)心得與文章.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末翼馆,一起剝皮案震驚了整個(gè)濱河市懊悯,隨后出現(xiàn)的幾起案子氢惋,更是在濱河造成了極大的恐慌缎浇,老刑警劉巖检号,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件措左,死亡現(xiàn)場(chǎng)離奇詭異依痊,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)怎披,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門胸嘁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人凉逛,你說我怎么就攤上這事性宏。” “怎么了状飞?”我有些...
    開封第一講書人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵毫胜,是天一觀的道長(zhǎng)书斜。 經(jīng)常有香客問我,道長(zhǎng)酵使,這世上最難降的妖魔是什么荐吉? 我笑而不...
    開封第一講書人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮口渔,結(jié)果婚禮上样屠,老公的妹妹穿的比我還像新娘。我一直安慰自己缺脉,他們只是感情好痪欲,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著枪向,像睡著了一般勤揩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上秘蛔,一...
    開封第一講書人閱讀 52,156評(píng)論 1 308
  • 那天陨亡,我揣著相機(jī)與錄音,去河邊找鬼深员。 笑死负蠕,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的倦畅。 我是一名探鬼主播遮糖,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼叠赐!你這毒婦竟也來了欲账?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤芭概,失蹤者是張志新(化名)和其女友劉穎赛不,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體罢洲,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡踢故,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了惹苗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片殿较。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖桩蓉,靈堂內(nèi)的尸體忽然破棺而出淋纲,到底是詐尸還是另有隱情,我是刑警寧澤院究,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布帚戳,位于F島的核電站玷或,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏片任。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一蔬胯、第九天 我趴在偏房一處隱蔽的房頂上張望对供。 院中可真熱鬧,春花似錦氛濒、人聲如沸产场。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)京景。三九已至,卻和暖如春骗奖,著一層夾襖步出監(jiān)牢的瞬間确徙,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來泰國(guó)打工执桌, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鄙皇,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓仰挣,卻偏偏與公主長(zhǎng)得像伴逸,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子膘壶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359

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