2

この次のhelloworldCプログラムでは、Pythonの拡張と埋め込みの両方を行っています。

spam.c

#include <Python.h>

static PyObject *
spam_echo(PyObject *self, PyObject *args) {
    const char *command;
    int sts;

    if (!PyArg_ParseTuple(args, "s", &command))
        return NULL;
    sts = printf("%s\n", command);
    return Py_BuildValue("i", sts);
}

static PyMethodDef SpamMethods[] = {
    {"echo", spam_echo, METH_VARARGS, "Prints passed argument"},
    {NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC
initspam(void) {
    (void) Py_InitModule("spam", SpamMethods);
}

int main(int argc, char *argv[]) {
    PyObject *args;
    PyObject *arg;
    PyObject *result;
    PyObject *moduleName;
    PyObject *module;
    PyObject *func;

    Py_SetProgramName(argv[0]);
    Py_Initialize();
    initspam();

    PyRun_SimpleFile(fopen("foo.py", "r"), "foo.py");

    moduleName = PyString_FromString("__main__");
    module = PyImport_Import(moduleName);
    Py_DECREF(moduleName);
    if (!module) {
        return 1;
    }

    func = PyObject_GetAttrString(module, "foo");
    Py_DECREF(module);
    if (!func || !PyCallable_Check(func)) {
        return 1;
    }

    args = PyTuple_New(1);
    arg = Py_BuildValue("s", "hello world");
    PyTuple_SetItem(args, 0, arg);

    result = PyObject_CallObject(func, args);
    Py_DECREF(arg);
    Py_DECREF(args);
    Py_DECREF(func);

    printf("== before\n");
    Py_Finalize();
    printf("== after\n");
}

そして、これが呼び出されたPythonプログラムです:

foo.py

#!/usr/bin/python

import spam

def foo(cmd):
    spam.echo(cmd)

私はでコンパイルします

gcc spam.c -I/usr/include/python2.5/ -lpython2.5

GCC 4.2.4-1ubuntu4で、UbuntuHardyでpython2.5-devパッケージを使用しています。

基本的に、出力を示すように、Py_Finalizeにセグメンテーション違反があります。

hello world
== before
Segmentation fault
4

2 に答える 2

3

Py_DECREF(args);行を入れ替えてPy_DECREF(arg);問題を解決します。セグメンテーション違反は、すでに解放された後にアクセスargした結果でした。Py_DECREF(args)

于 2013-01-09T18:52:26.303 に答える
0

おそらく、行を交換することでPython2で修正されましたが、Python 3では修正されるべきではなく、確かに修正されませんでした。スニペットをもう一度見てください。

args = PyTuple_New(1);
arg = Py_BuildValue("s", "hello world");
PyTuple_SetItem(args, 0, arg);

PyTuple_Newと同様に、新しいオブジェクトを作成しますPy_BuildValue。ここで停止する場合は、はい、両方をDECREFする必要があります。

ただし、PyTuple_SetItem(args, 0, arg)の参照を盗みますarg。これはarg、タプルによって「所有」されていることを意味しargsます。あなたはもはや責任を負わないargので、それを非難すべきではありません。

argsがDECREFの場合、各アイテムをDECREFし、を処理しargます。(Py_REFCNT())を使用して、必要に応じて確認します。

つまり、たとえば、arg2つのリストに入れたい場合は、1回INCREFする必要があります。

args1 = PyTuple_New(1);
args2 = PyTyple_New(1);
arg = Py_BuildValue("s", "hello world");
PyTuple_SetItem(args1, 0, arg);
PyTyple_SetItem(args2, 0, arg);
Py_INCREF(arg);

したがって、args1が削除されると、args2で問題を引き起こすことなく、argを1回DECREFできます。

SetItemの後であっても、作成後はどこでもINCREF(arg)を実行できることに注意してください。これは、スコープ内にあります。

于 2020-05-25T15:33:23.070 に答える