Я пишу модуль расширения Python 2.7 в Китоне. Как создать объект Python, реализующий интерфейс буфера нового стиля, который обертывает кусок памяти, предоставленный мне библиотекой C? Блок памяти - это всего лишь строка байтов, а не структура или многомерный массив. Мне дается указатель const void *
и длина, а также некоторые сведения о том, как долго указатель остается действительным.Как обернуть указатель и длину C в объект буфера нового стиля в Cython?
Я не могу скопировать память - это убьет производительность для моего приложения.
С объектами буфера старого стиля я мог бы просто использовать PyBuffer_FromMemory()
, но я не могу найти такой же простой способ создания объекта буфера нового типа.
Должен ли я создать свой собственный класс, который реализует интерфейс буфера? Или Cython предоставляет простой способ сделать это?
Я читал Unicode and Passing Strings и Typed Memoryviews страниц из документации Cython, но документация неточна и не очень полная, и нет примеров, похожих на то, что я хочу сделать.
Вот что я пытался (test.pyx
):
from libc.stdlib cimport malloc
from libc.string cimport memcpy
## pretend that this function is in some C library and that it does
## something interesting. (this function is unrelated to the problem
## I'm experiencing -- this is just an example function that returns a
## chunk of memory that I want to wrap in an object that follows the
## new buffer protocol.)
cdef void dummy_function(const void **p, size_t *l):
cdef void *tmp = malloc(17)
memcpy(tmp, "some test\0 bytes", 17)
p[0] = tmp
l[0] = 17
cpdef getbuf():
cdef const void *cstr
cdef size_t l
dummy_function(&cstr, &l)
## error: test.pyx:21:20: Invalid base type for memoryview slice: void
#cdef const void[:] ret = cstr[:l]
## error: test.pyx:24:9: Assignment to const 'ret'
#cdef const char[:] ret = cstr[:l]
## error: test.pyx:27:27: Cannot convert 'void const *' to memoryviewslice
#cdef char[:] ret = cstr[:l]
## this next attempt cythonizes, but raises an exception:
## $ python -c 'import test; test.getbuf()'
## Traceback (most recent call last):
## File "<string>", line 1, in <module>
## File "test.pyx", line 15, in test.getbuf (test.c:1411)
## File "test.pyx", line 38, in test.getbuf (test.c:1350)
## File "stringsource", line 614, in View.MemoryView.memoryview_cwrapper (test.c:6763)
## File "stringsource", line 321, in View.MemoryView.memoryview.__cinit__ (test.c:3309)
## BufferError: Object is not writable.
cdef char[:] ret = (<const char *>cstr)[:l]
## this raises the same exception as above
#cdef char[:] ret = (<char *>cstr)[:l]
return ret
Возможно, это неудачно, потому что вы используете 'const char *' вместо 'char *'? – Kevin
@Kevin: Я обновил свой вопрос, чтобы указать, что такое же исключение происходит, даже если я передал 'char *' вместо 'const char *'. Спасибо что подметил это. –
Изучив проблему более подробно, я хотел бы указать, что memcpy является незаконным. Вы объявили 'tmp' как const, а затем изменили его. Это неопределенное поведение по стандарту C. Поскольку вы также сказали, что пытаетесь избежать копирования памяти, я немного запутался в этом вопросе. – Kevin