在接下来的hello world C程序中,我正在扩展和嵌入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,我在Ubuntu Hardy上使用python2.5-dev包。
基本上,我在Py_Finalize上有一个段错误,显示输出:
hello world
== before
Segmentation fault
答案 0 :(得分:2)
交换行Py_DECREF(args);
和Py_DECREF(arg);
可以解决问题。段错误是在arg
已经被释放后访问Py_DECREF(args)
的结果。
答案 1 :(得分:0)
也许交换行已将其修复为Python2,但它本来不是必须的,对于Python 3来说肯定不会。
args = PyTuple_New(1);
arg = Py_BuildValue("s", "hello world");
PyTuple_SetItem(args, 0, arg);
PyTuple_New
和Py_BuildValue
一样创建一个新对象。如果要停在那儿,是的,您应该同时对这两者进行解码。
但是,PyTuple_SetItem(args, 0, arg)
窃取了arg
的引用。这意味着arg
现在已由元组args
“拥有”。您不再对arg
负责,因此不应拒绝它。
当args
为DECREF时,它将对其每个项目进行DECREF,这将处理arg
。 (如果需要,请使用Py_REFCNT()
进行验证。
例如,这意味着,如果您想将arg
放入两个列表中,则需要对它进行一次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
删除后,它可以一次对REFREF arg,而不会引起args2的问题。
请注意,即使在创建SetItem之后,也可以在创建它之后的任何地方INCREF(arg)。