【问题标题】:dll export function to ctypesdll导出函数到ctypes
【发布时间】:2021-11-17 09:22:15
【问题描述】:

背景

我有一些用 C++ 编写的函数,它们需要很高的实时性能。我想快速将这些函数导出为动态链接库以暴露给 Python,以便我可以进行一些高级编程。

在这些函数中,为了方便使用,我使用中的PyList_New来收集一些中间数据。但是我遇到了一些错误。

代码示例

我发现核心问题是我不能事件导出 python 对象。编译源码为dll并使用ctypes加载后,结果显示

OSError: exception: access violation reading 0x0000000000000008

C++ 代码:

#include <Python.h>


#ifdef _MSC_VER
#define DLL_EXPORT  __declspec( dllexport )
#else
#define DLL_EXPORT
#endif

#ifdef __cplusplus
extern "C"{
#endif

DLL_EXPORT PyObject *test3() {
    PyObject* ptr = PyList_New(10);
    return ptr;
}

#ifdef __cplusplus
}
#endif

Python 测试代码:


if __name__ == "__main__":
    import ctypes

    lib = ctypes.cdll.LoadLibrary(LIB_DLL)
    
    test3 = lib.test3
    test3.argtypes = None
    test3.restype = ctypes.py_object
    
    print(test3())

环境配置

Clion with Microsoft Visual Studio 2019 Community,arch 是 amd64。

我知道,正确的方法是使用推荐的方法将使用 Python/C Api 的 C++ 源代码包装到模块中,但似乎我必须编写很多代码。有人可以帮忙吗?

【问题讨论】:

    标签: python c++ ctypes


    【解决方案1】:

    ctypes 通常用于调用“常规”C 函数,而不是 Python C API 函数,但可以这样做。您必须使用PyDLL 来加载使用 Python 的函数,因为它不会释放使用 Python 函数时需要持有的 GIL(全局解释器锁)。但是,您显示的代码无效,因为它没有填充它创建的列表(使用 OP 代码作为 test.c):

    >>> from ctypes import *
    >>> lib = PyDLL('./test')
    >>> lib.test3.restype=py_object
    >>> lib.test3()
    [<NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>]
    

    相反,正常编写 C 或 C++ 函数:

    test.cpp

    #ifdef _MSC_VER
    #define DLL_EXPORT  __declspec( dllexport )
    #else
    #define DLL_EXPORT
    #endif
    
    #ifdef __cplusplus
    extern "C"{
    #endif
    
    DLL_EXPORT int* create(int n) {
        auto p = new int[n];
        for(int i = 0; i < n; ++i)
            p[i] = i;
        return p;
    }
    
    DLL_EXPORT void destroy(int* p) {
        delete [] p;
    }
    
    #ifdef __cplusplus
    }
    #endif
    

    test.py

    from ctypes import *
    
    lib = CDLL('./test')
    lib.create.argtypes = c_int,
    lib.create.restype = POINTER(c_int)
    lib.destroy.argtypes = POINTER(c_int),
    lib.destroy.restype = None
    
    p = lib.create(5)
    print(p) # pointer to int
    print(p[:5]) # convert to list...pointer doesn't have length so slice.
    lib.destroy(p) # free memory
    

    输出:

    <__main__.LP_c_long object at 0x000001E094CD9DC0>
    [0, 1, 2, 3, 4]
    

    【讨论】:

      【解决方案2】:

      我自己解决了。只需更改为 Release 即可解决所有问题。

      【讨论】:

      • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
      猜你喜欢
      • 2011-02-22
      • 2020-07-30
      • 1970-01-01
      • 2021-11-03
      • 1970-01-01
      • 1970-01-01
      • 2012-12-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多