5

这个问题与我之前提出的问题有关。如果有人感兴趣,那就是这个基本上,我想做的是使用Py_buffer包装在memoryview-object 中的 C 数组向 Python 公开。我已经使用它来工作PyBuffer_FillInfo(工作=我可以在 Python 中操作数据并将其写入 C 中的标准输出),但是如果我尝试滚动我自己的缓冲区,我会在 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函数返回后的段错误。我真的不明白为什么会发生这种情况。非常感激任何的帮助。

编辑 根据这个我之前没找到的问题,itemsize > 1 可能根本不被支持。这使得这个问题更加有趣。也许我可以使用PyBuffer_FillInfo足够大的内存块来保存我想要的东西(例如 32 个 C 浮点数)。在这种情况下,问题更多是关于如何将 Python 浮点数分配给memoryviewPython 函数中的对象。提问提问。

4

1 回答 1

4

因此,在缺乏答案的情况下,我决定采用另一种方法,而不是我最初打算的方法。把这个留在这里,以防其他人遇到同样的障碍。

基本上,不是在 C 中创建缓冲区(或字节数组,等价)并将其传递给 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

我希望这可以帮助别人。

于 2013-03-08T10:53:15.957 回答