在Python中使用ctypes的回调函数中的c_void_p参数
我经常使用ctypes这个库,但遇到了一些我无法解释的事情。
首先,当我用c_void_p定义一个回调函数时,这个回调会接收到一个普通的整数。
我看到一些其他的帖子提到,当使用c_void_p作为返回值时,可以把它包裹在另一个POINTER里。所以,我想我可以在回调函数的参数定义中试试用POINTER(c_void_p)。现在当回调被调用时,我得到了一个指针,但我还是不知道它指向的是否是有效的数据。
因为c_void_p指向的是一个包含二进制数据的缓冲区,我不认为我可以用c_char_p。我尝试把它转换成一个无符号字符的数组,长度是我接收到的,但Python告诉我我得到的是一个元组,并没有“内容”或“值”这样的属性可以使用。
有什么建议吗?
1 个回答
7
在回调函数中接收到一个 c_void_p
类型的整数是很正常的。这是因为它使用了简单类型的 getfunc
来进行自动转换——就像把 c_void_p
当作 Structure
字段一样。ctypes 不会对简单类型的子类进行自动转换,比如 type('my_void_p', (c_void_p,), {})
。不过我觉得在这个情况下这并不重要。
假设你在 p
中有一个整数地址。你可以用以下任意一种方法将其转换为长度为 n
的 c_char
数组:
buf = cast(p, POINTER(c_char * n))[0]
# 2.6+
buf = (c_char * n).from_address(p)
也就是说,既然知道它是一个 char *
类型,我会定义回调函数使用 POINTER(c_char)
。然后可以通过索引或切片来访问这个缓冲区,比如 p[0]
或 p[:n]
。
*p[n]
相当于 *(p + n)
,其中 *
是解引用操作符,"+" 是基于引用大小的指针运算。你可以使用 p.contents
来代替 p[0]
,但后者也会调用类型的 getfunc
转换器(如果适用的话)。