如何从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. 

这不会C_library_function名称C_library_function和链接器将在其input* .lib文件中find相同的名称,并解决问题。

从C调用C ++函数?

但是在这里我扩展了一个用C编写的大型应用程序,我需要使用一个用C ++编写的库。 C ++的名字在这里引起麻烦。 链接器抱怨未解决的符号。 那么我不能在我的C项目上使用C ++编译器,因为那会破坏很多其他的东西。 什么是出路?

顺便说一下我使用MSVC

您需要创build一个C API来公开您的C ++代码的function。 基本上,您将需要编写C ++代码,声明为extern“C”,并且具有包装C ++库的纯C C API(例如,不使用类)。 然后你使用你创build的纯C包装库。

即使C不是面向对象,您的C API也可以select遵循面向对象的风格。 例如:

  // *.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); } 

我会这样做:

(如果使用MSVC,忽略GCC编译命令)

假设我有一个名为AAA的C ++类,在文件aaa.h,aaa.cpp中定义, AAA类有一个名为sayHi(con​​st char * name)的方法 ,我想为C代码启用。

AAA类的C ++代码 – 纯C ++,我不修改它:

// aaa.h

 #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 ++中也创build一个C连接器。 在文件aaa_c_connector.h,aaa_c_connector.cpp中定义它。 这个连接器将定义一个名为AAA_sayHi(cosnt char * name)的C函数,它将使用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(con​​st char * name) 。 我现在可以创build一个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。 注意

假设C ++ API是C兼容的(没有类,模板等),你可以用extern "C" { ... }来包装它,就像你用另一种方法做的那样。

如果你想暴露对象和其他可爱的C ++的东西,你将不得不编写一个包装API。

如果你想这样做,你将不得不在C ++中编写一个C封装器。 C ++向后兼容,但是C不是向前兼容的。

将C ++函数导出为ex​​tern“C”(又名C样式符号),或者使用.def文件格式为C ++连接器创buildC ++库时定义未装饰的导出符号,那么C连接器不应该读取它