extern C 學習筆記

2021-06-29 13:29:39 字數 2520 閱讀 2503

1.引言

有一道經典的程式設計師面試題,如下:

//為什麼標準標頭檔案都有和以下 相似的結構?
#ifndef duniangheadfile

#define duniangheadfile

#ifdef __cplusplus

extern "c"

#endif

#endif /* duniangheadfile */

對於標頭檔案中的編譯巨集的作用,顯然是為了防止該標頭檔案被重複引用。

#ifndef duniangheadfile

#define duniangheadfile

#endif /* duniangheadfile */

那麼剩下**的作用又是什麼呢?

#ifdef __cplusplus

extern "c"

#endif

這正是本篇博文所要闡述的內容。下面我們進入正題。

2.揭密extern "c"

從直觀上來講,extern "c" 顯然有兩層含義。其一,是 被它修飾的目標是「extern」,即該目標具有外部鏈結性,可以在其他編譯單元(檔案)中被引用。其二,被它修飾的目標是「c」型別的,即編譯器或鏈結器要按照c的編譯規則來對其進行編譯或鏈結。

之所以採用這種方式,是因為c和c++這兩種語言之間的一些差異導致的。

作為一種物件導向的語言,c++支援函式過載,而過程式語言c則不支援。函式被c++編譯後在符號庫中的名字與c語言的不同。例如,假設某個函式的原型為:

int myfunc(int a, int b);
經過c++編譯器編譯之後 ,在其目標檔案.o 檔案中,有乙個_z10myfuncii 符號,這個符號就代表了原始檔中的int myfunc(int a, int b)函式了。不同的編譯器可能生成不同的名字,但是都採用了相同的機制,即c++ primer中所說的「名字粉碎」(name mangling)或「名字修飾」(name decoration)。

_z10myfuncii 這樣的名字包含了函式名、函式引數數量及型別資訊,其最後的兩個字元i 就表示第一引數和第二引數都是整型。c++就是靠這種機制來實現函式過載的。在鏈結階段,鏈結器就會從生成的 .o目標檔案中尋找_z10myfuncii 這樣的符號,從而生成可執行檔案。

而對於加extern "c"宣告後,即假設某個函式的原型為:

#ifdef __cplusplus

extern "c"

#endif

編譯生成myfunc函式的目標**時,沒有對其名字進行特殊處理,採用了c語言的方式;鏈結器在為其他的目標**尋找myfunc函式呼叫時,尋找的是未經修改的符號名_myfunc。正是因為如此,才實現了c++與c及其它語言的混合程式設計。

3.extern "c"的慣用法

明白了c++中extern "c"的基本原理,下面我們來具體分析一下extern "c"的常用技巧。

(1)在c++中引用c語言中的函式和變數,在包含c語言標頭檔案(假設為cexample.h)時,需進行下列處理:

extern "c"

而在c語言的標頭檔案中,對其外部函式只能指定為extern型別,c語言中不支援extern "c"宣告,在c檔案的標頭檔案中直接extern "c"時會出現編譯語法錯誤。但是,說的是直接使用會出錯。如果略施小計,c語言標頭檔案中也是可以使用extern "c"的。

用g++編譯cpp程式時,編譯器會定義巨集 __cplusplus ,可根據__cplusplus是否已經定義,來決定是否需要extern "c"。

#ifdef __cpluscplus  

extern "c"

#endif

這是你可以修改c語言.h檔案的情況。

(2)當你不能修改c語言.h檔案,比如這個標頭檔案是公司裡的前輩寫的,或者,公司規定禁止修改沒有bug的歷史遺留**,以防引入不必要的新bug。

同時,.h檔案中沒有extern "c"關鍵字,而你的c++程式又要鏈結使用由c編譯好的.o目標檔案。這時該怎麼辦呢?

可以這樣,在你的c++檔案中,包含該模組的標頭檔案時加上extern "c", 如下:

extern "c"
如果僅僅使用其中的乙個函式,而不需要include整個標頭檔案時,也可以單獨宣告該函式,如下:

extern "c"
這樣,c++編譯器在編譯,或鏈結器在鏈結的時候,就會以c風格在目標檔案中生成或尋找目標符號了。

同理,如果c++呼叫乙個c語言編寫的.dll時,當包括.dll的標頭檔案或宣告介面函式時,應加extern "c" 。這突然讓我想到了com元件技術。

extern 「C」 的學習總結

原因和目的 原因由於c 支援函式過載,而c語言不支援函式過載,因此c 編譯器在編譯c 函式生成的函式符號和c語言編譯器編譯c函式生成的函式符號是有區別的,如下 int add int a,int b 使用c語言編譯器編譯生成的函式符號是 add 使用c 編譯器編譯生成的函式符號類似是 add int...

C語言學習之extern C

extern c 的主要作用就是為了能夠正確實現c 呼叫其他c語言 加上extern c 後,會指示編譯器這部分 按c語言的進行編譯,而不是c 的。由於c 支援函式過載,因此編譯器編譯函式的過程中會將函式的引數型別也加到編譯後的 中,而不僅僅是函式名 而c語言並不支援函式過載,因此編譯c語言 的函式...

C 學習軌跡之extern C作用

1.extern c 的主要作用就是為了能夠正確實現c 呼叫其他c語言 加上extern c 後,會指示編譯器這部分 按c語言 而不是c 的方式進行編譯。由於c 支援函式過載,因此編譯器編譯函式的過程中會將函式的引數型別也加到編譯後的 中,而不僅僅是函式名 而c語言並不支援函式過載,因此編譯c語言 ...