****如只想知道怎樣就能實(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ù)名稱相同, 而形參列表不同, 如下圖所示 :?
然而大家有沒有想過為什么C++支持函數(shù)重載, 而C卻不支持函數(shù)重載呢??
這個(gè)就要涉及到C++的名字改編機(jī)制了. 請(qǐng)往下看~
* C++的名字改編機(jī)制
在C中,?
void test(); // 該函數(shù)編譯后編譯器會(huì)對(duì)函數(shù)名稱改寫成 _test?
ps: 不提供test()函數(shù)的實(shí)現(xiàn)是讓Xcode鏈接的時(shí)候報(bào)錯(cuò), 這樣我們才能看清楚test()函數(shù)的真面目!
void test(int a); // 該函數(shù)編譯后編譯器改寫函數(shù)名后依然是 _test
在C++中,?
void test(); // 該函數(shù)編譯后編譯器會(huì)對(duì)函數(shù)名稱改寫成 test()
void test(int a); // 該函數(shù)編譯后編譯器改寫函數(shù)名后是 test(int)
ps : 有的系統(tǒng)的編譯器會(huì)編譯成 _test_int 這種格式, 名字改編機(jī)制只是一種思路, 并沒有一種唯一的命名規(guī)范, 不同的編譯器命名規(guī)范不同, 但是思路一致! 如下圖所示 :?
本文就舉這幾個(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", 可以用{ } 括住, 例如 :
那應(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++的代碼
廢話不多說, 上代碼.?
毫無(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ò)誤. 如下圖
解決思路很明確, 只要確保函數(shù)在C和C++文件中編譯鏈接的規(guī)約一樣就OK了!
這時(shí)候extern "C" 就要閃亮登場(chǎng)了!
此時(shí)我們只需要在cpp文件中用extern "C" { } 把需要被C文件調(diào)用的函數(shù)包含即可, 如下圖
* C++中調(diào)用C的代碼
此時(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"中, 如下圖
有的朋友可能就想到了, 既然函數(shù)聲明已經(jīng)被copy到了C++文件中, 只需要保證C++文件中的這段函數(shù)聲明代碼按照類C的編譯, 鏈接規(guī)約進(jìn)行編譯和鏈接就能保證編譯出的sum函數(shù)的名稱與C文件中的函數(shù)名稱保持一致了!
所以便有了以下方法
細(xì)心的朋友就會(huì)發(fā)現(xiàn), 既然#include相當(dāng)于文本拷貝, 那為何不把extern "C" 語(yǔ)句放到頭文件中呢?
好的, 我們?cè)囋噡
但是我很遺憾的告訴大家, 如果你這樣做的話, 那么C文件就不能調(diào)用C文件的方法了!
因?yàn)镃的編譯器不支持 extern "C" 語(yǔ)法!
這里要引出一個(gè)宏, __cplusplus, 只要是C++文件, 編譯器就會(huì)自動(dòng)定義一個(gè)這樣的宏, 我們就能利用這個(gè)宏做到C/C++的終極混編了!
總結(jié)
要想寫一套C/C++均能調(diào)用的函數(shù), 則必須按照C的方式編譯 (因?yàn)镃語(yǔ)言不支持C++, 而C++同時(shí)支持C/C++)
要實(shí)現(xiàn)C/C++混合編程其實(shí)很簡(jiǎn)單, 只需要在頭文件加幾行代碼即可, 如下圖
有趣的是, 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í)心得與文章.