我正在尝试在Linux中为本机库编写包装器。问题是:
c中的定义:
int mymethod(mystruct* ptr)
:
_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
错误。如何将结构作为指向本机方法的指针传递?
感谢。
METE
答案 0 :(得分:5)
问题是来自ctypes的更高级别的“POINTER”在Python中是一个不同的对象,而不是“一般指针”(ctypes.CArgObject
by 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)))
答案 1 :(得分:3)
(我知道这是一个老问题,但我认为接受的答案是一个不必要的解决方法,所以我想把这个留给后人。)
实际上ctypes应explicitly support使用byref()
来传递这样的指针:
ctypes导出
byref()
函数,该函数用于通过引用传递参数。使用pointer()
函数可以实现相同的效果,尽管pointer()
因为它构造了一个真正的指针对象而做了很多工作,所以如果不这样做,byref()
会更快需要Python本身的指针对象。
可能的原因是你已经在多个地方定义了你的结构(例如在不同的模块中) - 如果argtypes
赋值看到一个定义而函数调用看到另一个定义,则会出现这个令人困惑的错误。换句话说,ctypes尝试匹配两个mystruct
类型,这些类型的内容(可能)相同,并且具有完全相同的名称,但它们不是相同的类型。只要基本结构类型是单个类型对象,如果使用pointer()
,byref()
或POINTER()()
构造指向它的指针并不重要 - ctypes将检测到底层(指向)类型是相同的。
要验证是否是这种情况,请在调用外部函数之前尝试assert(_lib.mymethod.argtypes[0]._type_ == type(s))
。