如何将一片 memoryview 转换为 C 字符串(unsigned char*)?
How do I cast a slice of memoryview into C string (unsigned char*)?
下面是我遇到这个问题的代码:
cpdef object encode_file(object fin, str fout):
if not PyObject_CheckBuffer(fin):
raise TypeError("fin must follow the buffer protocol")
cdef Py_buffer in_view
cdef int ret_code = PyObject_GetBuffer(fin, &in_view, PyBUF_SIMPLE)
if ret_code < 0:
raise TypeError("Couldn't get buffer from fin")
cdef bytes py_filename = fout.encode()
cdef char* cy_filename = py_filename
cdef bytes py_mode = "w".encode()
cdef const char* mode = py_mode
cdef FILE* fd = fopen(<const char*>py_filename, <const char*>mode)
if <size_t>fd == 0:
raise FileNotFoundError(fout)
cdef unsigned char out_buff[256]
cdef size_t written = 0
cdef size_t total_written = 0
cdef size_t used = 0
cdef size_t total_used = 0
cdef size_t pad_start = 80
cdef unsigned char[:] char_view = fin
cdef unsigned char* char_slice
while total_used < <size_t>in_view.len:
char_view = char_view[used:]
# This is the place where I get the error
char_slice = char_view.buf
used = encode_buffer(
char_slice,
in_view.len - used,
out_buff,
256,
pad_start,
80,
&written,
)
pad_start = 80 - used % 80
total_written += written
total_used += used
if fwrite(out_buff, sizeof(char), used, fd) != used:
fclose(fd)
raise Exception(
"Couldn't write to file: {}. Bytes written: {}".format(
fout, total_used,
),
)
fclose(fd)
print "used: {}, written: {}".format(used, total_written)
return total_written
对于一个简单的例子来说,这可能是代码太多了,但如果你仔细想想,其实并没有那么多。循环之前的部分处理过滤掉各种边缘情况——他们对这个问题不感兴趣。唯一重要的部分是第一个参数必须实现缓冲区协议,第二个参数是文件名。
因此,为了写入文件,我想获取内存视图的一部分,然后将其传递给需要指向 unsigned char
的指针的 C 函数。对于我的一生,我不知道如何使用 Cython 来做到这一点......我尝试了上面代码的各种排列,但是,在大多数情况下我得到
Storing unsafe C derivative of temporary Python reference
没有任何关于它试图生成什么的提示。
上面的代码中也有一些重复,因为我不知道如何使用 in_view.buf[x]
并使其具有我需要的类型。我把它留在这里只是为了表明我也试过了。
类似问题的答案无效,因为 Cython 内存视图存在错误。如果有不同的答案,我将不胜感激。
鉴于您似乎无法使用内存视图,因为数据是只读的,您可以改用 Py_Buffer
对象。数据在 in_view.buf
中存储为 void*
。使用 <const char*>(in_view.buf)
将其转换为 const char*
。您可以通过简单的指针运算获得第 n
个元素(即只需将 n
添加到该值)。
由于您使用过 PyBuf_SIMPLE
,您知道项目大小为 1 且数组是连续的,但在更复杂的情况下,您可能不得不担心这一点。
下面是我遇到这个问题的代码:
cpdef object encode_file(object fin, str fout):
if not PyObject_CheckBuffer(fin):
raise TypeError("fin must follow the buffer protocol")
cdef Py_buffer in_view
cdef int ret_code = PyObject_GetBuffer(fin, &in_view, PyBUF_SIMPLE)
if ret_code < 0:
raise TypeError("Couldn't get buffer from fin")
cdef bytes py_filename = fout.encode()
cdef char* cy_filename = py_filename
cdef bytes py_mode = "w".encode()
cdef const char* mode = py_mode
cdef FILE* fd = fopen(<const char*>py_filename, <const char*>mode)
if <size_t>fd == 0:
raise FileNotFoundError(fout)
cdef unsigned char out_buff[256]
cdef size_t written = 0
cdef size_t total_written = 0
cdef size_t used = 0
cdef size_t total_used = 0
cdef size_t pad_start = 80
cdef unsigned char[:] char_view = fin
cdef unsigned char* char_slice
while total_used < <size_t>in_view.len:
char_view = char_view[used:]
# This is the place where I get the error
char_slice = char_view.buf
used = encode_buffer(
char_slice,
in_view.len - used,
out_buff,
256,
pad_start,
80,
&written,
)
pad_start = 80 - used % 80
total_written += written
total_used += used
if fwrite(out_buff, sizeof(char), used, fd) != used:
fclose(fd)
raise Exception(
"Couldn't write to file: {}. Bytes written: {}".format(
fout, total_used,
),
)
fclose(fd)
print "used: {}, written: {}".format(used, total_written)
return total_written
对于一个简单的例子来说,这可能是代码太多了,但如果你仔细想想,其实并没有那么多。循环之前的部分处理过滤掉各种边缘情况——他们对这个问题不感兴趣。唯一重要的部分是第一个参数必须实现缓冲区协议,第二个参数是文件名。
因此,为了写入文件,我想获取内存视图的一部分,然后将其传递给需要指向 unsigned char
的指针的 C 函数。对于我的一生,我不知道如何使用 Cython 来做到这一点......我尝试了上面代码的各种排列,但是,在大多数情况下我得到
Storing unsafe C derivative of temporary Python reference
没有任何关于它试图生成什么的提示。
上面的代码中也有一些重复,因为我不知道如何使用 in_view.buf[x]
并使其具有我需要的类型。我把它留在这里只是为了表明我也试过了。
类似问题的答案无效,因为 Cython 内存视图存在错误。如果有不同的答案,我将不胜感激。
鉴于您似乎无法使用内存视图,因为数据是只读的,您可以改用 Py_Buffer
对象。数据在 in_view.buf
中存储为 void*
。使用 <const char*>(in_view.buf)
将其转换为 const char*
。您可以通过简单的指针运算获得第 n
个元素(即只需将 n
添加到该值)。
由于您使用过 PyBuf_SIMPLE
,您知道项目大小为 1 且数组是连续的,但在更复杂的情况下,您可能不得不担心这一点。