5

この質問は、私が以前に尋ねた質問に関連しています。つまり、誰かが興味を持っているならこれ。基本的に、私がやりたいのは、 -objectでPy_bufferラップされたものを使用してC配列をPythonに公開することです。memoryview(work = Pythonでデータを操作し、Cでstdoutに書き込むことができます)を使用して動作するようになりましPyBuffer_FillInfoたが、自分のバッファーをロールしようとすると、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フロート)。その場合、問題はmemoryview、Python関数でオブジェクトにPythonフロートを割り当てる方法に関するものです。質問質問。

4

1 に答える 1

4

それで、答えがないので、私は当初意図したものとは別のアプローチを取ることにしました。他の誰かが同じ障害にぶつかった場合に備えて、これをここに残しておきます。

基本的に、Cでバッファー(またはbytearrayと同等)を作成し、拡張ユーザーが変更できるようにPythonに渡す代わりに。ユーザーがPythonコールバック関数からbytearray(またはバッファーインターフェイスをサポートする任意のタイプ)を返すように、コードを少し再設計しただけです。このように、アイテムのサイズについて心配する必要はありません。私の場合、返されたオブジェクトに対して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 に答える