2010-04-30 196 views
48

我知道這一點。如何從C調用C++函數?

從C++調用C函數:

如果我的應用程序是在C++和我不得不用C編寫的一個庫,然後我會用

//main.cpp 

extern "C" void C_library_function(int x, int y);//prototype 
C_library_function(2,4);// directly using it. 

此止跌調用函數」 t破解名稱C_library_function和鏈接器將在其輸入* .lib文件中找到相同的名稱,並解決問題。

調用C++從C函數???

但是我在這裏延伸的用C語言編寫的大型應用程序,我需要使用的是用C++庫。 C++的名稱改變在這裏引起麻煩。連接器抱怨未解決的符號。那麼我不能在我的C項目上使用C++編譯器,因爲那會破壞很多其他的東西。什麼是出路?

通過我使用的是MSVC

+4

閱讀http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html#faq-32.6 – jweyrich 2010-04-30 11:41:43

+0

當您控制C++庫時:http:// stackoverflow。 com/questions/12615683/calling-c-functions-from-c-file – 2015-05-29 10:10:50

+2

可能出現[從C中優雅地調用C++]的副本(http://stackoverflow.com/questions/7281441/elegantly-call-c-from-c ) – user2284570 2017-03-13 22:48:26

回答

59

你需要創建一個C API來暴露你的C++代碼的功能。基本上,您需要編寫C++代碼,聲明爲extern「C」,並且具有包裝C++庫的純C C API(例如,不使用類)。然後你使用你創建的純C包裝庫。

你的C API可以任意跟隨一個面向對象的風格,即使C不是面向對象的。例如:

// *.h file 
// ... 
#ifdef __cplusplus 
#define EXTERNC extern "C" 
#else 
#define EXTERNC 
#endif 

typedef void* mylibrary_mytype_t; 

EXTERNC mylibrary_mytype_t mylibrary_mytype_init(); 
EXTERNC void mylibrary_mytype_destroy(mylibrary_mytype_t mytype); 
EXTERNC void mylibrary_mytype_doit(mylibrary_mytype_t self, int param); 

#undef EXTERNC 
// ... 


// *.cpp file 
mylibrary_mytype_t mylibrary_mytype_init() { 
    return new MyType; 
} 

void mylibrary_mytype_destroy(mylibrary_mytype_t untyped_ptr) { 
    MyType* typed_ptr = static_cast<MyType*>(untyped_ptr); 
    delete typed_ptr; 
} 

void mylibrary_mytype_doit(mylibrary_mytype_t untyped_self, int param) { 
    MyType* typed_self = static_cast<MyType*>(untyped_self); 
    typed_self->doIt(param); 
} 
+0

謝謝!!得到它了。 http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html#faq-32.6 – claws 2010-04-30 11:49:44

+1

感謝您的回答。但是,鏈接被破壞。 – Milo 2013-04-23 15:24:09

+1

謝謝。我沒有意識到,當我刪除它時,仍然存在來自StackOverlow的該頁面的鏈接。我更新了答案,以提供更多詳細信息,而無需引用該頁面。 – 2013-05-09 09:52:36

2

出口你的C++函數爲extern「C」(又名空調風格符號),或使用DEF文件格式來定義的C++連接器未修飾的出口符號的方式,當創建C++庫,那麼C連接不應該有麻煩閱讀它

5

假設C++ API是C兼容(無類,模板等),你可以用它在extern "C" { ... },就像你走另一條路什麼時候。

如果你想公開對象和其他可愛的C++的東西,你必須寫一個包裝API。

+0

不太... C++庫需要重新編譯。 – 2010-04-30 11:41:59

+0

哦,不, C++ API完全是面向對象的。 – claws 2010-04-30 11:42:15

+2

@claws,請參閱我的關於製作OOP風格的C代碼的文章..並創建一個包含C接口但使用該風格的包裝器庫,但是是一個基礎的C++實現。然後鏈接到C界面。 – 2010-04-30 11:43:36

5

你將不得不寫了針對c包裝在C++中,如果你想這樣做。 C++向後兼容,但C不兼容。

17

我會做下列方式:

(如果有MSVC的工作,忽視了GCC編譯命令)

假設我有一個名爲AAA一個C++類,在文件中AAA中定義.h,aaa.cpp,並且類AAA有一個名爲sayHi(常量字符*名稱),我想啓用C代碼。

類的C++代碼AAA - 純C++,我不修改它:

// AAA。ħ

#ifndef AAA_H 
#define AAA_H 

class AAA { 
    public: 
     AAA(); 
     void sayHi(const char *name); 
}; 

#endif 

// aaa.cpp

#include <iostream> 

#include "aaa.h" 

AAA::AAA() { 
} 

void AAA::sayHi(const char *name) { 
    std::cout << "Hi " << name << std::endl; 
} 

編譯此類作爲定期對C++進行。這段代碼「不知道」它將被C代碼使用。使用命令:

g++ -fpic -shared aaa.cpp -o libaaa.so 

現在,同樣在C++,創建一個C連接器。在文件中定義它aaa_c_connector.h,aaa_c_connector.cpp。該連接器將定義一個C函數,命名爲AAA_sayHi(cosnt字符*姓名),將使用的實例AAA,並調用其方法:

// aaa_c_connector.h

#ifndef AAA_C_CONNECTOR_H 
#define AAA_C_CONNECTOR_H 

#ifdef __cplusplus 
extern "C" { 
#endif 

void AAA_sayHi(const char *name); 

#ifdef __cplusplus 
} 
#endif 


#endif 

// aaa_c_connector.cpp

#include <cstdlib> 

#include "aaa_c_connector.h" 
#include "aaa.h" 

#ifdef __cplusplus 
extern "C" { 
#endif 

// Inside this "extern C" block, I can define C functions that are able to call C++ code 

static AAA *AAA_instance = NULL; 

void lazyAAA() { 
    if (AAA_instance == NULL) { 
     AAA_instance = new AAA(); 
    } 
} 

void AAA_sayHi(const char *name) { 
    lazyAAA(); 
    AAA_instance->sayHi(name); 
} 

#ifdef __cplusplus 
} 
#endif 

編譯它,再次使用常規的C++編譯命令:

g++ -fpic -shared aaa_c_connector.cpp -L. -laaa -o libaaa_c_connector.so 

現在我有一個共享庫(libaaa_c_connector.so),實現了C函數AAA_sayHi(爲const char *名稱)。我現在可以創建一個C主文件和編譯它一起:

// main.c中

#include "aaa_c_connector.h" 

int main() { 
    AAA_sayHi("David"); 
    AAA_sayHi("James"); 

    return 0; 
} 

使用C編譯命令編譯它:

gcc main.c -L. -laaa_c_connector -o c_aaa 

我需要設置LD_LIBRARY_PATH包含$ PWD,如果我運行可執行./c_aaa,我會得到的輸出我預計:

Hi David 
Hi James 

編輯:

在一些Linux發行版,-laaa-lstdc++可能還需要進行最後的編譯命令。感謝@AlaaM。注意事項

+1

非常感謝。你的詳細回答幫了我很多。 – Abhinav 2016-09-08 14:51:20

+1

你也可以用'gcc usecpp.c -L指定lib鏈接路徑。 -laaa_c_connector -Wl,-rpath ,. -o c_aaa' – Metaphox 2016-10-04 10:49:17

+0

什麼是'usecpp.c'? – 2016-10-30 09:58:09