如果我有一个可写的
buffer
,我可以使用ctypes.c_void_p.from_buffer
函数来获取指向该缓冲区的C指针。
但是如何处理不可写的缓冲区呢?如何形成一个
const
指针,将其传递给需要 const void*
的 C 代码,而不需要制作不可写缓冲区的可写副本?
我考虑过
c_void_p.from_address
,但缓冲区(和内存视图)似乎没有公开它们的地址。
一些澄清:
>>> import ctypes
>>> b = buffer("some data that supports the buffer interface, like a str")
>>> ptr = ctypes.c_void_p.from_buffer(b)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: buffer is read-only
>>> ptr = ctypes.c_void_p.from_buffer_copy(b) # works, but has to copy data
>>> ptr = ctypes.CONST(c_void_p).from_buffer(b) # (I'm making this one up)
>>> ptr = ctypes.c_void_p.from_address(???) # could work; how to get addr?
这可以与
void some_api(const void* read_only_data)
一起使用,例如:
>>> ctypes.cdll.LoadLibrary(some_lib).some_api(ptr)
带有
from_buffer_copy
的方法可以工作,但需要先复制缓冲区。我正在寻找解决缓冲区可写要求的方法,因为没有人会在那里写入,并且我想避免数据的冗余复制。
您可以使用 ctypes 将 Python 字符串转换为
char*
,它指向存储 Python 字符串数据的实际内存。
随意双重投射。
对于
void*
,可以直接将 str/unicode
(Python 2.x) 或 bytes/str
(Python 3.x) 传递给函数。 它们将被编组为指向值字节的指针,或者在 Unicode 字符串的情况下,编组为指向字符串的适合操作系统的 UTF 编码字节的指针,例如Windows 上的 UTF-16LE。
示例(Python 3.x):
import ctypes as ct
crt = ct.CDLL('msvcrt')
# void* memcpy(void* dest, const void* src, size_t count);
memcpy = crt.memcpy
memcpy.argtypes = ct.c_void_p, ct.c_void_p, ct.c_size_t
memcpy.restype = ct.c_void_p
dest = ct.create_string_buffer(10) # writeable buffer
src = bytes([1,2,3,4,5]) # immutable bytes
print(dest.raw.hex(' '))
memcpy(dest, src, len(src))
print(dest.raw.hex(' '))
src = '马克😉' # immutable str (will marshal as UTF-16LE bytes on Windows)
memcpy(dest, src, len(src.encode('utf-16le')))
print(dest.raw.hex(' '))
print(dest.raw.decode('utf-16le'))
输出:
00 00 00 00 00 00 00 00 00 00
01 02 03 04 05 00 00 00 00 00
6c 9a 4b 51 3d d8 09 de 00 00
马克😉