c與c++的相互調用

最近項目須要使用google test(如下簡稱爲gtest)做爲單元測試框架,可是項目自己過於龐大,main函數無從找起,須要將gtest框架編譯成靜態庫使用。由於項目自己是經過純c語言編寫,而gtest則是一個c++編寫的測試框架,其中必然涉及c與c++之間的相互調用。注意,本文的前提是,c代碼採用gcc等c語言編譯器編譯c代碼,採用g++等c++編譯器編譯c++代碼,若是c和c++代碼統一使用g++編譯,大部分狀況是能夠實現二者代碼相互調用的。如下爲踩坑過程的總結o_O||。ios

c與c++的函數區別

要了解二者之間如何實現相互調用,必須先了解c與c++之間的函數有什麼不一樣。c++

c++做爲c語言的升級版,二者必然有不少不一樣之處。其中有一個重大不一樣點就是,c++支持函數重載,而c語言不支持。爲了使函數支持重載,c++在c語言的基礎上,將函數名添加上返回值和參數的類型信息。例如,int add(int, int)這個函數,經過c++編譯器編譯後,可能呈現的函數名爲int int_add_int_int(int, int)(注:此處爲大概地說明c++是如何將返回值和參數信息添加到函數名中的,實際中編譯器不必定是這樣實現的)。框架

從以上說明能夠得出,因爲c++對函數重載的支持,使得編譯後的函數符號與c語言的不一致,即便是在二者函數名相同的前提下。函數

extern "C"的做用

那麼,c與c++是不能相互調用了嗎?答案是否認的,由於存在着extern "C"這個關鍵字可使語句能夠按照類C的編譯和鏈接規約來編譯和鏈接,而不是C++的編譯的鏈接規約。這樣在類C的代碼中就能夠調用C++的函數or變量等。單元測試

注意:extern "C"指令中的"C",表示的一種編譯和鏈接規約,而不是一種語言。"C"表示符合C語言的編譯和鏈接規約的任何語言,如Fortran、assembler等。測試

還有要說明的是,extern "C"指令僅指定編譯和鏈接規約,但不影響語義。例如在函數聲明中,指定了extern "C",仍然要遵照C++的類型檢測、參數轉換規則。google

c++中調用c代碼

對於c++,因爲c++的編譯器對c語言兼容,所以在c++中調用c語言編寫的函數,只須要在函數聲明前面加上關鍵字extern "C",表示採用類c語言的方式解析函數符號。例子以下:spa

// add.h

#ifdef __ADD_H__
#define __ADD_H__

extern "C" int add(int a, int b);

#endif


// add.c

int add(int a, int b)
{
    return a + b;
}


// main.cc

#include <iostream>
#include "add.h"
using namespace std;

int main()
{
    cout << "1 + 1 = " << add(1, 1) << endl;
}

在例子中,main.cc爲c++代碼,add.c爲c語言代碼,當c++編譯器識別到extern "C"`關鍵字時,會去尋找add函數的實現而不是尋找相似int_add_int_int這樣帶參數信息的函數實現。code

c語言調用c++代碼

c語言調用c++代碼卻並不容易,緣由是c語言並不兼容c++。就算c語言能夠調用c++,也會由於沒法識別c++新定義的符號而編譯報錯。所以,爲了實現c語言調用c++函數,必須實現如下兩個步驟:1. 將c++相關函數封裝爲靜態庫或動態庫(由於調用庫函數時編譯器並不知道里面執行的是什麼語言);2. 對外提供遵循類c語言規約的接口函數。例子以下所示:接口

// printNum.h

#ifdef __PRINTNUM_H__
#define __PRINTNUM_H__

extern "C" void printNum(int a);

#endif


// printNum.cc

#include <iostream>
#include "printNum.h"
using namespace std;

void printNum(int a)
{
    cout << << "num is " << a << endl;
}


// main.c

extern void printNum(int a);

printNum(5);

經過將cout函數封裝爲類c語言規約的接口函數,使得main.c中能夠成功調用c++函數printNum。值得注意的是,main.c不能夠直接引入printNum.h,由於c語言不能識別extern "C"關鍵字。能夠利用c++預約義宏實現頭文件的改寫:

#ifdef __PRINTNUM_H__
#define __PRINTNUM_H__

#ifdef __cplusplus
extern "C" { 
#endif
void printNum(int a);

#ifdef __cplusplus
}
#endif

#endif

小結

小結以下:

  1. c語言與c++的相互調用能夠經過extern "C"關鍵字實現
  2. c++中調用c代碼,只須在c++中爲c代碼函數聲明以前加上extern "C"
  3. c語言調用c++代碼,則須要將c++代碼編譯成靜態庫或動態庫,而後對外提供用extern "C"聲明的類c封裝函數
相關文章
相關標籤/搜索