类型。如何通过引用传递结构?

Posted

技术标签:

【中文标题】类型。如何通过引用传递结构?【英文标题】:Ctypes. How to pass struct by reference? 【发布时间】:2020-03-25 04:48:31 【问题描述】:

我尝试使用 ctypes 为 C 库编写 Python 包装器。 到目前为止,我有:

C.h


    typedef struct
    
        int erorrCode;
        char * Key;

     A;

    #ifdef __cplusplus
    extern "C" 
    #endif

    EXPORT void __stdcall DestroyA(A &input);

    #ifdef __cplusplus
    
    #endif

C.cpp


    EXPORT void __stdcall DestroyA(A &input)
    
        delete []input.Key;
    

Python.py


    import sys
    import ctypes

    class A(ctypes.Structure):
        _fields_ = [
            ("erorrCode", ctypes.c_int),
            ("Key", ctypes.c_char_p)]


    try:
      libapi = ctypes.cdll.LoadLibrary('./lib.so')
    except OSError:
      print("Unable to load RAPI library")
      sys.exit()

    DestroyA = libapi.DestroyA
    libapi.DestroyA.argtypes = [ctypes.POINTER(A)]
    libapi.DestroyA.restype = None

    a = A(1,b'random_string')

    DestroyA(ctypes.byref(a)) #!!!here is segmentation fault 

那么,我该如何解决分段错误错误?

注意:只要有办法在 Python 端修复它,我就无法更改 C++ 端的代码。

【问题讨论】:

为什么你的函数是__stdcall 您确定要拨打DestroyA吗?因为您在这里a = A(1,b'random_string') 在Python 中分配c_char_p。因此 Python 应该为其分配的对象处理内存。这意味着您的库函数不管理它应该“删除”的地址并给您一个分段错误。 另一件事是您正试图调用一个标记为__stdcall 的函数。但是您的库加载为 CDLL ctypes.cdll.LoadLibrary,这意味着 dll 导出应该有 __cdecl(请参阅此处 docs.python.org/3/library/…)。 【参考方案1】:

上市[Python.Docs]: ctypes - A foreign function library for Python。

您在此处未定义行为 (UB)。

Python 为其对象(包括 CTypes 对象)内置了内存管理。 所以,每当一个对象(PyObject 基本上是任何东西 - 包括一个 Python int),Python 在后台调用 malloc 函数系列之一以分配内存。相反,当对象被销毁(手动或通过GC)时,free 被调用。

发生了什么:

    您创建了对象(在幕后,Python 分配了一些内存) 你在Python分配的对象上调用了free(这是错误的,更何况你还越过了.dll边界)

您需要调用 free 仅在您分配的指针上。一个这样的例子:[SO]: python: ctypes, read POINTER(c_char) in python (@CristiFati's answer)。

如果你想摆脱对象(从而释放它使用的内存),让 Python 为你做:

del a

补充说明:

您将 __stdcall 函数与 ctypes.CDLL 一起使用。同样,这是 UB(在 32 位 上)。使用“常规”调用约定 (__cdecl)

您正在传递一个引用。这是 C++ 特定的(虽然它只是一个 const ptr)。要与 C 兼容,请使用:

EXPORT void destroyA(A *pInput);

【讨论】:

以上是关于类型。如何通过引用传递结构?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过引用传递结构?

通过不同类型的引用传递参数时如何进行类型转换

无法通过引用传递typedef结构

通过引用与值传递对象

如何打印通过引用传递的 glm::vec3 类型的向量值?

C# 通过引用传递属性