我使用ctypes接口到外部库。这个库返回给我一个二进制缓冲区。界面看起来像这样:
int getBuff(unsigned char **buf, int *len);
图书馆还会导出一个deallocator,以便在完成时可以释放缓冲区,但是这方面对我没有任何问题,所以我认为我们不需要覆盖。
在我的CTYPES代码中,我将buf
参数表示为c_void_p
。我想尽可能有效地将此缓冲区复制到字节对象中。
目前我有:
data = bytes(bytearray(ctypes.cast(buf, ctypes.POINTER(ctypes.c_ubyte*len.value))[0]))
其中buf
是c_void_p
,len
是c_int
。
我理解,这执行了两个副本。一旦到达bytearray对象,然后再次到达字节对象。
我只能只用一个副本执行此操作?
我目前的努力集中在Python 2上,但是在适当的时候,我也需要为Python 3提供支持。
显然您可以切成CTYPES指针。不是c_void_p
,c_char_p
或c_wchar_p
,而是POINTER
类型。对于POINTER(c_char)
,切片为您提供bytes
:
data = ctypes.POINTER(ctypes.c_char).from_buffer(buf)[:len.value]
感谢Eryksun提出了这一点。另外,尚不清楚为什么buf
是c_void_p
而不是已经是POINTER(c_char)
。(对于POINTER(c_char)
,代码仅为buf[:len.value]
。(
用于从支持缓冲协议的一般对象中获取bytes
,memoryview(...).tobytes()
涉及比bytes(bytearray(...))
少的复制:
data = memoryview(ctypes.cast(buf, ctypes.POINTER(ctypes.c_ubyte*len.value))[0]).tobytes()
这与Python 2和Python 3。
兼容请记住,这里的buf
必须是指向缓冲区的指针,而不是指向缓冲区指针的指针。getBuff
将指针指向指针(因此可能byref(buf)
(。