[轉(zhuǎn)]C++中的extern “C”用法詳解

原文

這篇文章主要介紹了C++中的extern “C”用法詳解,簡單來說,extern “C”是C++聲明或定義C語言符號的方法,是為了與C兼容,需要的朋友可以參考下

簡單來說赊豌,extern “C”是C++聲明或定義C語言符號的方法,是為了與C兼容。說來容易菜拓,要理解起來還是得費(fèi)些周折惠啄,首先我們要從C++和C的區(qū)別說起。
符號
大家都知道,從代碼到可執(zhí)行程序需要經(jīng)過編譯和鏈接兩個過程瘟忱,其中編譯階段會做語法檢測香缺,代碼展開手销,另外它還會做一件事,就是將變量轉(zhuǎn)成符號图张,鏈接的時候其實(shí)是通過符號來定位的锋拖。編譯器在編譯C和C++代碼時,將變量轉(zhuǎn)成符號的過程是不同的祸轮。本文所使用的編譯器為gcc4.4.7
我們先來看一段簡單的代碼
復(fù)制代碼 代碼如下:

/* hello.c */

include <stdio.h>

const char* g_prefix = "hello ";

void hello(const char* name)
{
printf("%s%s", g_prefix, name);
}

注意兽埃,這里的文件名為hello.c,我們執(zhí)行編譯gcc -c hello.c得到目標(biāo)文件hello.o适袜,在Linux下用nm查看目標(biāo)文件的符號表得到如下結(jié)果($符號代表shell命令提示符)
復(fù)制代碼 代碼如下:

$ nm hello.o
0000000000000000 D g_prefix
0000000000000000 T hello
U printf

這是C代碼編譯后的符號列表柄错,其中第三列為編譯后的符號名,我們主要看自己定義的全局變量g_prefix和函數(shù)hello,它們的編譯后的符號名和代碼里的名字是一樣的鄙陡。我們將hello.c重命名為hello.cpp冕房,重新編譯gcc -c hello.cpp得到hello.o,在用nm查看趁矾,結(jié)果如下
復(fù)制代碼 代碼如下:

0000000000000000 T _Z5helloPKc
U __gxx_personality_v0
0000000000000000 D g_prefix
U printf

這是C++代碼編譯后的符號列表耙册,gcc會自動根據(jù)文件后綴名來識別C和C++代碼,這時我們發(fā)現(xiàn)g_prefix的符號沒變毫捣,但函數(shù)hello的符號變成了Z5helloPKc详拙,這就說明gcc在編譯C和C++代碼時處理方式是不一樣的,對于C代碼蔓同,變量的符號名就是變量本身(在早期編譯器會為C代碼變量前加下劃線饶辙,現(xiàn)在默認(rèn)都不會了,在編譯時可以通過編譯選項(xiàng)-fno-leading-underscore和-fleading-underscore來顯式設(shè)置),而對于C++代碼,如果是數(shù)據(jù)變量并且沒有嵌套巴帮,符號名也是本身涝缝,如果變量名有嵌套(在名稱空間或類里)或者是函數(shù)名郭毕,符號名就會按如下規(guī)則來處理
1、 符號以_Z開始
2、 如果有嵌套,后面緊跟N涌矢,然后是名稱空間、類快骗、函數(shù)的名字娜庇,名字前的數(shù)字是長度,以E結(jié)尾
3方篮、 如果沒嵌套名秀,則直接是名字長度后面跟著名字
4、 最后是參數(shù)列表藕溅,類型和符號對應(yīng)關(guān)系如下
復(fù)制代碼 代碼如下:

int    -> i  
float  -> f  
double -> d  
char   -> c  
void   -> v  
const  -> K  
*      -> P  

這樣就很好理解為什么C++代碼里的void hello(const char*)編譯之后符號為_Z5helloPKc(PKc翻譯成類型要從右到左翻譯為char const 匕得,這是編譯器內(nèi)部的表示方式,我們習(xí)慣的表示方式是const char蜈垮,兩者是一樣的),c++filt工具可以從符號反推名字裕照,使用方法為c++filt _Z5helloPKc
下面列舉幾個函數(shù)和符號的對應(yīng)例子

這樣也很容易理解為什么C++支持函數(shù)重載而C不支持了攒发,因?yàn)镃++將函數(shù)修飾為符號時把函數(shù)的參數(shù)類型加進(jìn)去了,而C卻沒有晋南,所以在C++下惠猿,即便函數(shù)名相同,只要參數(shù)不同负间,它們的符號名是不會沖突的偶妖。我們可以通過下面一個例子來驗(yàn)證變量名和符號的這種關(guān)系姜凄。
復(fù)制代碼 代碼如下:

/ * filename : test.cpp */

include <stdio.h>

namespace myname
{
int var = 42;
}

extern int _ZN6myname3varE;

int main()
{
printf("%d\n", _ZN6myname3varE);
return 0;
}
這里我們在名稱空間namespace定義了全局變量var,根據(jù)前面的內(nèi)容趾访,它會被修飾為符號_ZN6myname3varE态秧,然后我們手動聲明了外部變量_ZN6myname3varE并將其打印出來。編譯并運(yùn)行扼鞋,它的值正好就是var的值
復(fù)制代碼 代碼如下:

$ gcc test.cpp -o test -lstdc++
$ ./test
42
extern "C"
有了符號的概念我們再來看extern “C”的用法就很容易了
復(fù)制代碼 代碼如下:

extern "C"
{
int func(int);
int var;
}

它的意思就是告訴編譯器將extern “C”后面的括號里的代碼當(dāng)做C代碼來處理申鱼,當(dāng)然我們也可以以單條語句來聲明
復(fù)制代碼 代碼如下:

extern "C" int func(int);
extern "C" int var;
這樣就聲明了C類型的func和var。很多時候我們寫一個頭文件聲明了一些C語言的函數(shù)云头,而這些函數(shù)可能被C和C++代碼調(diào)用捐友,當(dāng)我們提供給C++代碼調(diào)用時,需要在頭文件里加extern “C”溃槐,否則C++編譯的時候會找不到符號匣砖,而給C代碼調(diào)用時又不能加extern “C”,因?yàn)镃是不支持這樣的語法的昏滴,常見的處理方式是這樣的猴鲫,我們以C的庫函數(shù)memset為例
復(fù)制代碼 代碼如下:

ifdef __cplusplus

extern "C" {

endif

void memset(void, int, size_t);

ifdef __cplusplus

}

endif

其中__cplusplus是C++編譯器定義的一個宏,如果這份代碼和C++一起編譯影涉,那么memset會在extern "C"里被聲明变隔,如果是和C代碼一起編譯則直接聲明,由于__cplusplus沒有被定義蟹倾,所以也不會有語法錯誤匣缘。這樣的技巧在系統(tǒng)頭文件里經(jīng)常被用到。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鲜棠,一起剝皮案震驚了整個濱河市肌厨,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌豁陆,老刑警劉巖柑爸,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異盒音,居然都是意外死亡表鳍,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進(jìn)店門祥诽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來譬圣,“玉大人,你說我怎么就攤上這事雄坪±迨欤” “怎么了?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長绳姨。 經(jīng)常有香客問我登澜,道長,這世上最難降的妖魔是什么飘庄? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任脑蠕,我火速辦了婚禮,結(jié)果婚禮上竭宰,老公的妹妹穿的比我還像新娘空郊。我一直安慰自己,他們只是感情好切揭,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布狞甚。 她就那樣靜靜地躺著,像睡著了一般廓旬。 火紅的嫁衣襯著肌膚如雪哼审。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天孕豹,我揣著相機(jī)與錄音涩盾,去河邊找鬼。 笑死励背,一個胖子當(dāng)著我的面吹牛春霍,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播叶眉,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼址儒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了衅疙?” 一聲冷哼從身側(cè)響起莲趣,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎饱溢,沒想到半個月后喧伞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡绩郎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年潘鲫,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片肋杖。...
    茶點(diǎn)故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡溉仑,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出兽愤,到底是詐尸還是另有隱情彼念,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布浅萧,位于F島的核電站逐沙,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏洼畅。R本人自食惡果不足惜吩案,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望帝簇。 院中可真熱鬧徘郭,春花似錦、人聲如沸丧肴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽芋浮。三九已至抱环,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間纸巷,已是汗流浹背镇草。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瘤旨,地道東北人梯啤。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像存哲,于是被迫代替她去往敵國和親因宇。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評論 2 355

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