Python可以调用使用外部"C"编译的C ++ DLL库吗?与ctypes? [英] Can Python call C++ DLL libraries compiled using extern "C" with ctypes?

查看:50
本文介绍了Python可以调用使用外部"C"编译的C ++ DLL库吗?与ctypes?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

互联网上有很多文章说Python无法使用 ctypes 访问C ++编译的DLL,还有其他相互矛盾的文章说,只要DLL,就可以访问DLL.使用外部"C" 方法进行编译.所以我只想澄清一下.如果外部的"C"是否可能用了吗?

There are many articles on the internet that say that Python cannot access C++ compiled DLLs using ctypes, and there are other contradictory articles which say that it is possible to access the DLL so long as the DLL is compiled with the extern "C" method. So I just want clarification. Is it possible if extern "C" is used ?

推荐答案

有C ++编译的dll可以与 ctypes 一起使用,而C ++编译的dll不能与 ctypes一起使用直接.

There are C++-compiled dlls which can be used with ctypes and C++-compiled dlls which cannot be used with ctypes directly.

如果API仅公开纯旧数据(例如 int int * char * 等),并包装在 extern"C" 中,然后就可以从 ctypes 中使用它.

If API exposes only plain-old-data (e.g. int, int *, char * and similar) and is wrapped in extern "C" then it can be consumed from ctypes.

如果接口中使用了非POD类(例如 std :: vector std :: string ),或者API未包装在中>外部"C" ,则该dll无法与 ctypes 一起使用(至少以一种可移植的方式并且没有太多麻烦).

If non-POD-classes are used (for example std::vector or std::string) in interfaces or the API isn't wrapped in extern "C" then the dll cannot be used with ctypes (at least in a portable way and without much ado).

为什么需要外部"C" ?

Why extern "C" is needed?

以下声明在C ++中有效,但在C中无效:

Following declarations are valid in C++ but not in C:

void my_fun(int a);
void my_fun(double a);

由于C不执行名称修饰,这两个函数都将映射到结果对象文件中名为 my_fun 的符号,这是有问题的.

Because C doesn't perform name mangling, both functions would be mapped to a symbol named my_fun in the resulting object file, which is problematic.

C ++将创建两个名称不正确的符号,例如gcc将创建符号 Z6my_funi _Z6my_fund .MSVC具有另一种命名方案-因此dll(或共享库)中的最终符号取决于生成它的编译器.

C++ would create two different symbols with mangled names, for example gcc would create symbols Z6my_funi and _Z6my_fund. MSVC has another naming scheme - so the resulting symbols in the dll (or shared object) depends on the compiler with which it was built.

ctypes 的帮助下,在dll中找到这些符号并不是没有可能-只是不像C名称那样简单,因为一个人需要更多信息-dll是与哪个编译器一起使用的构建.

It is not impossible to find these symbols in the dll with help of ctypes - it is only not as straight forward as with C-names because one needs additional information - with which compiler the dll was build.

C名称与 ctypes 即开即用,并且将声明包装到 extern"C" 中会关闭名称处理,因此

C-names work out of the box with ctypes, and wrapping declarations into extern "C" switches the name mangling off, thus

extern "C" {
  void my_fun(int a);
  void my_fun(double a);
}

将不再编译,因为编译器将确保符号没有多个定义.

would no longer compile, as compiler will ensure that there are no multiple definitions of a symbol.

为什么不能在接口中使用更复杂的C ++类?

外部"C" 禁止使用 std :: vector<> 和其他C ++类:

extern "C" doesn't forbid usage of std::vector<> and other C++-classes:

extern "C" {
  void my_fun(std::vector<double> a);
}

编译时,它仅生成符号 my_func 而不是?my_fun @@ YANV?$ vector @ NV?$ allocator @ N @ std @@@ std @@@ Z >(使用MSVC)或 _Z6my_funSt6vectorIdSaIdEE (使用gcc)在生成的目标文件中.

compiles, it only produces symbol my_func instead of ?my_fun@@YANV?$vector@NV?$allocator@N@std@@@std@@@Z (with MSVC) or _Z6my_funSt6vectorIdSaIdEE (with gcc) in the resulting object file.

在使用POD时,假设 double [10] ,其内存布局清晰明了,例如 std :: vector 依赖于实现,并且 ctypes 未知.另一个问题是-某些 ctypes 也无法处理的问题-构造函数/析构函数,比简单的POD初始化要复杂的多.

While for PODs, let's say double[10], the memory layout is clear, the memory layout of e.g. a std::vector is implementation dependent and is not known to ctypes. Another issue are - something ctypes doesn't handle as well - constructors/destructors which can be more complicated than simple initialization of PODs.

因此, my_fun(std :: vector< double>)的功能不能与 ctypes 一起使用.但是,如果知道类的内存布局,则可以使用 ctypes 模拟它们,并通过调用()构造函数(顺便说一句,即使包装在 extern"C" 中,类方法的符号也总是被弄乱),调用函数 my_fun 并然后通过调用(正确的)析构函数销毁对象.

Thus the functionality of my_fun(std::vector<double>) cannot be used out-of-the-box with ctypes. However, if one knows the memory layout of the classes, one could emulate them with ctypes, initialize objects by calling (right) constructors (btw. symbols of class-methods are always mangled, even if wrapped in extern "C"), call the function my_fun and then destroy objects by calling (right) destructors.

这篇关于Python可以调用使用外部"C"编译的C ++ DLL库吗?与ctypes?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆