cla*_*aws 74 c c++ visual-c++ extern-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.
Run Code Online (Sandbox Code Playgroud)
这不会破坏名称C_library_function,链接器会在其输入*.lib文件中找到相同的名称,问题就解决了.
从C ???调用C++函数
但是在这里我扩展了一个用C语言编写的大型应用程序,我需要使用一个用C++编写的库.C++的名称错误导致了麻烦.Linker抱怨未解决的符号.好吧,我不能在我的C项目中使用C++编译器,因为这会破坏很多其他东西.出路是什么?
顺便说一句,我正在使用MSVC
Mic*_*yan 85
您需要创建一个C API来公开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);
}
Run Code Online (Sandbox Code Playgroud)
Som*_*ing 33
我会用以下方式做到这一点:
(如果使用MSVC,请忽略GCC编译命令)
假设我有一个名为AAA的C++类,在文件aaa.h,aaa.cpp中定义,并且AAA类有一个名为sayHi(const char*name)的方法,我想为C代码启用它.
类AAA的C++代码- 纯C++,我不修改它:
// aaa.h
#ifndef AAA_H
#define AAA_H
class AAA {
public:
AAA();
void sayHi(const char *name);
};
#endif
Run Code Online (Sandbox Code Playgroud)
// aaa.cpp
#include <iostream>
#include "aaa.h"
AAA::AAA() {
}
void AAA::sayHi(const char *name) {
std::cout << "Hi " << name << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
像C++一样定期编译这个类.此代码"不知道"它将被C代码使用.使用命令:
g++ -fpic -shared aaa.cpp -o libaaa.so
Run Code Online (Sandbox Code Playgroud)
现在,也是在C++中,创建一个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
Run Code Online (Sandbox Code Playgroud)
// 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 implement functions in C++, which will externally
// appear as C functions (which means that the function IDs will be their names, unlike
// the regular C++ behavior, which allows defining multiple functions with the same name
// (overloading) and hence uses function signature hashing to enforce unique IDs),
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
Run Code Online (Sandbox Code Playgroud)
再次使用常规C++编译命令对其进行编译:
g++ -fpic -shared aaa_c_connector.cpp -L. -laaa -o libaaa_c_connector.so
Run Code Online (Sandbox Code Playgroud)
现在我有一个共享库(libaaa_c_connector.so),它实现了C函数AAA_sayHi(const char*name).我现在可以创建一个C主文件并将它们一起编译:
// main.c
#include "aaa_c_connector.h"
int main() {
AAA_sayHi("David");
AAA_sayHi("James");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
使用C编译命令编译它:
gcc main.c -L. -laaa_c_connector -o c_aaa
Run Code Online (Sandbox Code Playgroud)
我需要将LD_LIBRARY_PATH设置为包含$ PWD,如果我运行可执行文件./c_aaa,我将得到我期望的输出:
Hi David
Hi James
Run Code Online (Sandbox Code Playgroud)
编辑:
在某些Linux发行版上,aaa.h也aaa.cpp可能是最后一次编译命令所必需的.感谢@AlaaM.为了引起注意
假设C++ API是C兼容的(没有类,模板等),你可以将它包装进去extern "C" { ... },就像你走另一条路一样.
如果你想暴露对象和其他可爱的C++东西,你将不得不编写一个包装器API.