这个问题与我之前提出的一个问题有关。即this one,如果有人感兴趣的话。基本上,我想要做的是使用封装在Py_buffer
中的memoryview
-object向Python公开一个C数组。我已经让它使用PyBuffer_FillInfo
(work =我可以用Python操作数据并将其写入C中的stdout ),但是如果我试图滚动自己的缓冲区,则在C函数返回后得到一个分段错误。
我需要创建自己的缓冲区,因为PyBuffer_FillInfo假定格式是char,使itemsize字段为1,我需要能够提供大小为1、2、4和8的项。
一些代码,这是一个有用的例子:
Py_buffer *buf = (Py_buffer *) malloc(sizeof(*buf));
int r = PyBuffer_FillInfo(buf, NULL, malloc(sizeof(char) * 4), 4, 0, PyBUF_CONTIG);
PyObject *mv = PyMemoryView_FromBuffer(buf);
//Pack the memoryview object into an argument list and call the Python function
for (blah)
printf("%c\n", *buf->buf++); //this prints the values i set in the Python function
看看PyBuffer_FillInfo
的实现,它非常简单,我滚动了自己的函数,以便能够提供自定义项目大小:
//buffer creation function
Py_buffer *getReadWriteBuffer(int nitems, int itemsize, char *fmt) {
Py_buffer *buf = (Py_buffer *) malloc(sizeof(*buf));
buf->obj = NULL
buf->buf = malloc(nitems * itemsize);
buf->len = nitems * itemsize;
buf->readonly = 0;
buf->itemsize = itemsize;
buf->format = fmt;
buf->ndim = 1;
buf->shape = NULL;
buf->strides = NULL;
buf->suboffsets = NULL;
buf->internal = NULL;
return buf;
}
我如何使用它:
Py_buffer *buf = getReadWriteBuffer(32, 2, "h");
PyObject *mv = PyMemoryView_FromBuffer(buf);
// pack the memoryview into an argument list and call the Python function as before
for (blah)
printf("%d\n", *buf->buf); //this prints all zeroes even though i modify the array in Python
return 0;
//the segfault happens somewhere after here
使用我自己的缓冲区对象的结果是C函数返回后的分段错误。我真的不明白为什么会发生这种事。任何帮助都将不胜感激。
根据this question编辑,我以前没有找到,项目大小>1甚至可能根本不受支持。这使得这个问题更加有趣。也许我可以使用PyBuffer_FillInfo
,有足够大的内存块来容纳我想要的东西(例如32C浮点数)。在这种情况下,更多的问题是如何将Python分配给Python函数中的memoryview
对象。提问问题。
发布于 2013-03-08 02:53:15
因此,在缺乏答案的情况下,我决定采取另一种方法,而不是我最初想要的方法。把这个留在这里以防别人遇到同样的麻烦。
基本上,而不是创建一个缓冲区(或字节数组,等价物)。并将其传递给Python,以供扩展用户修改。我只是稍微重新设计了代码,这样用户就可以从Python回调函数返回字节数组(或支持缓冲区接口的任何类型)。这样,我甚至不需要担心条目的大小,因为在我的示例中,C代码对返回的对象所做的一切就是提取它的缓冲区并使用简单的memcpy
将其复制到另一个缓冲区。
代码:
PYGILSTATE_ACQUIRE; //a macro i made
PyObject *result = PyEval_CallObject(python_callback, NULL);
if (!PyObject_CheckBuffer(result))
; //raise exception
Py_buffer *view = (Py_buffer *) malloc(sizeof(*view));
int error = PyObject_GetBuffer(result, view, PyBUF_SIMPLE);
if (error)
; //raise exception
memcpy(my_other_buffer, view->buf, view->len);
PyBuffer_Release(view);
Py_DECREF(result);
PYGILSTATE_RELEASE; //another macro
我希望这能帮上忙。
https://stackoverflow.com/questions/15244255
复制相似问题