說明:本文主要內容參考了吳秦(Tyler)的部落格,並結合自己的情況,做了一些修改。如果想瞭解更多的規則,請參考吳秦(Tyler)的部落格。
最近在做QT和DVSDK的混合編程,找到了一個嵌入式超聲波檢測儀的例子來學習(MIDAS Ultrasound v3.0 Demo),裡面的標頭檔很多都是類似於如下聲明:
宏 #ifndef 、#define、#endif 的作用大家肯定都非常瞭解了,主要是為了防止在一個項目中,標頭檔被多次包含。本文簡單討論一下 extern "C" { } 的作用。
extern "C" 的作用是實作類別C(代表的是跟C語言的編譯和串連方式一致的所有語言)和C++的混合編程。
要明白 C 和 C++ 的互相調用,你得知道它們之間的編譯和串連差異。
1、C++ 的編譯和串連機制
C++是一個物件導向語言(雖不是純粹的物件導向語言),它支援函數的重載,重載這個特性給我們帶來了很大的便利。為了支援函數重載的這個特性,C++編譯器實際上將下面這些重載函數:
這樣的函數名,來唯一標識每個函數。註:不同的編譯器實現可能不一樣,但是都是利用這種機制。所以當串連是調用 print(3) 時,它會去尋找 _print_int(3) 這樣的函數。下面說個題外話,正是因為這點,重載被認為不是多態,多態是運行時動態綁定(“一種介面多種實現”),如果硬要認為重載是多態,它頂多是編譯時間“多態”。
C++中的變數,編譯也類似,如全域變數可能編譯g_xx,類變數編譯為c_xx等。串連是也是按照這種機制去尋找相應的變數。
2、C 的編譯和串連機制
C語言中並沒有重載和類這些特性,故並不像C++那樣 print(int i) ,會被編譯為 _print_int ,而是直接編譯為 _print 等。因此如果直接在C++中調用C的函數會失敗,因為串連是調用C中的 print(3) 時,它會去找 _print_int(3) 。因此 extern "C" 的作用就體現出來了。
瞭解了C和C++的編譯機制,接下來,我們就分別介紹如何在C++中調用C的代碼、C中調用C++的代碼。
1、C++ 中調用 C 的代碼
假設一個C的標頭檔 cHeader.h 中包含一個函數 print(int i) :
相應的實現檔案 cHeader.c 的代碼為:
現在在C++的代碼檔案 main.cpp 中引用C中的 print(int i) 函數:
執行程式輸出:
2、C 中調用 C++ 的代碼
現在換成在C中調用C++的代碼,這與在C++中調用C的代碼有所不同。如下在 cppHeader.h 標頭檔中定義了下面的代碼:
相應的實現檔案cppHeader.cpp檔案中代碼如下:
在C的代碼檔案 main.c 中調用 print 函數:
注意在C的代碼檔案中直接 #include "cppHeader.h" 標頭檔,編譯出錯。而且如果不加 extern void print(int i) 編譯也會出錯。