在Python中使用ctypes的回调函数中的c_void_p参数

4 投票
1 回答
1977 浏览
提问于 2025-04-18 04:04

我经常使用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 中有一个整数地址。你可以用以下任意一种方法将其转换为长度为 nc_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 转换器(如果适用的话)。

撰写回答