python ctypes将指向结构的指针作为参数发送到本机库

met*_*ete 6 python struct ctypes pointers

我正在尝试在Linux中为本机库编写包装器.问题是这样的:

c中的定义:

int mymethod(mystruct* ptr)

在python中:

_lib.mymethod.argtypes = (ctypes.POINTER(mystruct),)
_lib.mymethod.restype = ctypes.c_int

s = mystruct()

_lib.mymethod(ctypes.byref(s))
引发:预期的LP_mystruct实例而不是指向mystruct的指针

_lib.mymethod(ctypes.pointer(s))
引发预期的LP_mystruct实例而不是LP_mystruct

错误.如何将结构作为指向本机方法的指针传递?

谢谢.

丈量

jsb*_*eno 6

问题是来自ctypes的更高级别的"POINTER"在Python中是一个不同的对象,而不是返回的"通用指针"(ctypes.CArgObjectby ctypes.byref)或表示内存地址的单个数字(这是ctype返回的adrresof) -您可以注释您的功能以接收`ctypes.c_voidp并调用它_lib.mymethod(ctypes.addressof(a))-

或者如果你想在强制类型的一方工作以避免会导致Python崩溃的错误(类型错误会引发Python异常 - 传递给C语言的错误参数会导致Python解释器本身出现分段错误),你必须创建一个变量来保存新的"类型",它是您的结构的指针 - 然后使用您的结构地址创建此类型的实例:

mystruct_pointer = ctypes.POINTER(mystruct)
_lib.mymethod.argtypes = (mystruct_pointer,)
_lib.mymethod.restype = ctypes.c_int

s = mystruct()

_lib.mymethod(mystruct_pointer.from_address(ctypes.addressof(s)))
Run Code Online (Sandbox Code Playgroud)


Emi*_*rke 5

(我知道这是一个老问题,但我认为接受的答案是一种不必要的解决方法,所以我想把它留在这里以供后代使用。)

实际上 ctypes 应该明确支持usingbyref()传递这样的指针:

ctypes 导出byref()用于通过引用传递参数的函数。使用该pointer()函数可以实现相同的效果,但pointer()由于它构造了一个真正的指针对象,因此做了更多的工作,因此byref()如果您不需要 Python 本身的指针对象,则使用它会更快。

造成这种情况的可能原因是您在多个地方(例如,在不同的模块中)定义了结构 - 如果argtypes赋值看到一个定义而函数调用看到另一个定义,则会出现这种令人困惑的错误。换句话说,ctypes 尝试匹配mystruct内容(可能)相同的两种类型,并且具有完全相同的名称,但它们不是相同的类型。只要基本结构类型是单一类型对象,使用或- ctypes构造指向它的指针都没有关系pointer(),ctypes 将检测到基础(指向)类型是否相同。byref()POINTER()()

要验证是否是这种情况,请assert(_lib.mymethod.argtypes[0]._type_ == type(s))在调用外部函数之前尝试。