3

Python プログラムの C 拡張では、メインの C 関数 (何百万回も呼び出される) への 2 つの入力をグローバル変数として設定することでパフォーマンスを改善しようとしています。ラムダラッパーを使用してPythonからC関数にそれらを供給し続ける必要はありません(これはかなりの時間を無駄にします)。私のコードは次のようになります。まず、ファイルの先頭でグローバル変数を宣言します。

unsigned char* splitArray;
PyObject* wordCmp;

次に、Python API 関数を使用してそれらを設定します。

static PyObject* py_set_globals(PyObject *self, PyObject *args)
{
    free(wordCmp);
    free(splitArray);

    char* splitChars;
    PyObject* wordC;

    if (!PyArg_ParseTuple(args, "sO", &splitChars, &wordC))
        return NULL;

    wordCmp = (PyObject*)malloc(sizeof(PyObject));
    memcpy(wordCmp, wordC, sizeof(PyObject));
    splitArray = splitchars_to_mapping(splitChars);

    return Py_BuildValue("");
}

この場合、splitArray は関数 splitchars_to_mapping で malloc される 128 文字の配列に割り当てられ、wordCmp は C に渡される Python 関数オブジェクトです。とにかく、私が知る限り、char* splitArray は機能しますグローバル変数としては問題ありませんが、後で PyEval_CallObject を使用して wordCmp を呼び出そうとすると、Python/C がクラッシュします。だから私は2つの質問があります:

  1. 関数の先頭にある初期化されていないポインター wordCmp と splitArray を解放しようとすると、C がすぐにクラッシュしないのはなぜですか?
  2. wordCmp をヒープに適切に保存し、それへの参照をグローバルとして保存したのに、後で wordCmp を呼び出すことができないのはなぜですか?
4

1 に答える 1

3

最初の質問については、初期化されていないグローバル変数を解放してもクラッシュしないのはなぜですか。これは、グローバル (および静的) 変数がzero、プログラムのロード時 (標準で保証されている) および(またはゼロfree()で) 呼び出したときに初期化されるためです。 NULL) 何もしません。

man free(1)から:

free(ptr) が既に呼び出されている場合、未定義の動作が発生します。 ptr が NULL の場合、何も実行されません。

編集PyObject: 2 番目の質問は、PyObject構造体にポインターが含まれている可能性があり、その構造体にアクセスできないためディープコピーを実行できないため、a をコピーしようとしているという事実に関連しています。ただし、参照カウントをインクリメントし、後で使用するために参照を保持する必要があります。ドキュメントOから、参照カウントを使用する場合はインクリメントされないことに注意してください。

O (オブジェクト) [PyObject *] Python オブジェクトを (変換せずに) C オブジェクト ポインターに格納します。したがって、C プログラムは、渡された実際のオブジェクトを受け取ります。オブジェクトの参照カウントは増加しません。

したがって、参照を自分でインクリメントする必要があります。この例を参照してください

static PyObject *my_callback = NULL;

static PyObject* my_set_callback(PyObject *dummy, PyObject *args)
{
    PyObject *result = NULL;    
    if (PyArg_ParseTuple(args, "O:set_callback", &my_callback)) {
        if (!PyCallable_Check(my_callback)) {
            PyErr_SetString(PyExc_TypeError, "parameter must be callable");
            return NULL;
        }
        Py_XINCREF(my_callback); /* Add a reference to new callback */           
        Py_INCREF(Py_None);      /* Boilerplate to return "None" */
        result = Py_None;
    }
    return result;
}
于 2012-11-05T18:43:08.577 に答える