如何将 C 类与 ctypes 一起使用?

新手上路,请多包涵

我刚刚开始使用 ctypes,并且想使用我使用 ctypes 从 python 中导出到 dll 文件中的 C++ 类。所以假设我的 C++ 代码看起来像这样:

 class MyClass {
  public:
    int test();
...

我会知道创建一个包含此类的 .dll 文件,然后使用 ctypes 在 python 中加载 .dll 文件。现在我将如何创建一个 MyClass 类型的对象并调用它的测试函数? ctypes甚至可能吗?或者,我会考虑使用 SWIG 或 Boost.Python,但 ctypes 似乎是小型项目最简单的选择。

原文由 jörg 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.3k
2 个回答

简短的故事是,C++ 没有像 C 那样的标准二进制接口。不同的编译器为相同的 C++ 动态库输出不同的二进制文件,这是由于名称修改和处理库函数调用之间的堆栈的不同方式。

因此,不幸的是,实际上并没有一种可移植的方式来访问 C++ 库 但是,对于一次一个编译器来说,这没问题。

这篇博 文还简要概述了为什么目前这不起作用。也许在 C++0x 出来之后,我们会有一个标准的 C++ ABI?在那之前,您可能无法通过 Python 的 ctypes 访问 C++ 类。

原文由 Mark Rushakoff 发布,翻译遵循 CC BY-SA 2.5 许可协议

除了 Boost.Python(对于需要 C++ 类到 python 类的一对一映射的大型项目,这可能是一个更友好的解决方案),您可以在 C++ 端提供一个 C 接口。它是众多解决方案中的一种,因此它有自己的权衡取舍,但我将介绍它以使那些不熟悉该技术的人受益。为了全面披露,使用这种方法不会将 C++ 连接到 python,而是将 C++ 连接到 C 到 Python。下面我提供了一个满足您要求的示例,以向您展示 C++ 编译器的 extern “c” 工具的一般概念。

 //YourFile.cpp (compiled into a .dll or .so file)
#include <new> //For std::nothrow
//Either include a header defining your class, or define it here.

extern "C"  //Tells the compile to use C-linkage for the next scope.
{
    //Note: The interface this linkage region needs to use C only.
    void * CreateInstanceOfClass( void )
    {
        // Note: Inside the function body, I can use C++.
        return new(std::nothrow) MyClass;
    }

    //Thanks Chris.
    void DeleteInstanceOfClass (void *ptr)
    {
         delete(std::nothrow) ptr;
    }

    int CallMemberTest(void *ptr)
    {

        // Note: A downside here is the lack of type safety.
        // You could always internally(in the C++ library) save a reference to all
        // pointers created of type MyClass and verify it is an element in that
        //structure.
        //
        // Per comments with Andre, we should avoid throwing exceptions.
        try
        {
            MyClass * ref = reinterpret_cast<MyClass *>(ptr);
            return ref->Test();
        }
        catch(...)
        {
           return -1; //assuming -1 is an error condition.
        }
    }

} //End C linkage scope.

您可以使用以下代码编译此代码

gcc -shared -o test.so test.cpp
#creates test.so in your current working directory.

在您的 python 代码中,您可以执行以下操作(显示 2.7 的交互式提示):

 >>> from ctypes import cdll
>>> stdc=cdll.LoadLibrary("libc.so.6") # or similar to load c library
>>> stdcpp=cdll.LoadLibrary("libstdc++.so.6") # or similar to load c++ library
>>> myLib=cdll.LoadLibrary("/path/to/test.so")
>>> spam = myLib.CreateInstanceOfClass()
>>> spam
[outputs the pointer address of the element]
>>> value=CallMemberTest(spam)
[does whatever Test does to the spam reference of the object]

我确信 Boost.Python 在幕后做了类似的事情,但也许理解较低级别的概念会有所帮助。如果您尝试访问 C++ 库的功能并且不需要一对一映射,我会对这种方法感到更加兴奋。

有关 C/C++ 交互的更多信息,请查看 Sun 的此页面:http: //dsc.sun.com/solaris/articles/mixing.html#cpp_from_c

原文由 AudaAero 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题