【发布时间】:2014-07-19 05:06:07
【问题描述】:
我知道我不能使用 FFI 加载 C++ DLL(只有 C 可以工作),那么我该怎么做呢?如果我需要使用包装器,我该如何开始呢?
编辑: 我无法以任何方式更改 DLL。
【问题讨论】:
我知道我不能使用 FFI 加载 C++ DLL(只有 C 可以工作),那么我该怎么做呢?如果我需要使用包装器,我该如何开始呢?
编辑: 我无法以任何方式更改 DLL。
【问题讨论】:
您可以使用 C++ DLL。您需要像这样导出函数(在 MSVC 中):
extern "C" __declspec(dllexport)
由于 C++ 名称修改(用于重载),您的函数签名将与 C 命名不同。比如这个函数:
int foo(char* a, int b, double c)
可能使用 C++ 命名导出为 foo@12abunchoflettershere 之类的东西,而不是使用 C 命名的 foo。
请注意extern "C"不代表你的代码是纯C,你可以正常使用C++。这仍然有效:
extern "C" __declspec(dllexport) void foo(char *a, int b, std::shared_ptr<Foo> ptr)
【讨论】:
extern "C" 的整点是the C++ compiler doesn't mangle the name。如果您使用extern "C",则不必担心名称错误。
extern "C",然后立即说“函数签名将与C 命名不同”,这对于C 函数是不正确的。
您可以尝试在 FFI cdefs 中手动修改名称,但不同的编译器使用不同的名称修改方案,更不用说引用函数会很尴尬。
我建议不要手动修改 cdef 中的名称,而是建议用 C 编写一些包装器。虽然繁琐,但并不难。它的要点是它的 C 端将类视为不透明的结构,以传递给包装函数。不过,See this site 了解更多详情和一些问题。
这是我用于 Box2D 的包装器的示例 sn-p:
#include <Box2D/Box2D.h>
#ifdef __linux__
#define CEXPORT extern "C"
#else
#define CEXPORT extern "C" __declspec(dllexport)
#endif
// ///////////////////////////////////////////////////////
// World
CEXPORT b2World* b2World_new(b2Vec2* gravity) {
return new b2World(*gravity);
}
CEXPORT void b2World_destroy(b2World* world) {
delete world;
}
CEXPORT b2Body* b2World_createBody(b2World* world, const b2BodyDef* def) {
return world->CreateBody(def);
}
CEXPORT void b2World_destroyBody(b2World* world, b2Body* body) {
world->DestroyBody(body);
}
CEXPORT void b2World_step(b2World* world, float32 timeStep, int32 velIters, int32 posIters) {
world->Step(timeStep, velIters, posIters);
}
CEXPORT b2Body* b2World_getBodyList(b2World* world) {
return world->GetBodyList();
}
以及对应的cdecl:
typedef struct b2World b2World;
b2World* b2World_new(b2Vec2*);
void b2World_destroy(b2World*);
b2Body* b2World_createBody(b2World*, const b2BodyDef*);
void b2World_destroyBody(b2World*, b2Body* body);
void b2World_step(b2World*, float, int32_t, int32_t);
b2Body* b2World_getBodyList(b2World*);
【讨论】: