我在C中编写了一个不可变的链表类,但是一种方法是神秘的segfaulting。该代码旨在大致相当于:
class PList(object):
def __init__(self, first, rest=None):
self.first = first
self.rest = rest
def cons(self, item):
return PList(item, self)
这是我的代码:
#include <Python.h>
#include <structmember.h>
static PyTypeObject PListType;
typedef struct PListStruct{
PyObject_HEAD
PyObject *first;
struct PListStruct *rest;
} PList;
static PyMemberDef plist_members[] = {
{"first", T_OBJECT_EX, offsetof(PList, first), READONLY, "First element"},
{"rest", T_OBJECT_EX, offsetof(PList, rest), READONLY, "Rest of the list"},
{NULL}
};
static PyObject *
PList_cons(PList *self, PyObject *arg)
{
PList *new_list = PyObject_CallFunctionObjArgs(&PListType, arg, self);
Py_INCREF(new_list);
return new_list;
}
static PyMethodDef plist_methods[] = {
{"cons", (PyCFunction)PList_cons, METH_O, "Add an item to the list"},
{NULL}
};
static void PList_dealloc(PList *self)
{
Py_XDECREF(self->first);
Py_XDECREF(self->rest);
self->ob_type->tp_free((PyObject*)self);
}
static int
PList_init(PList *self, PyObject *args, PyObject *kwds)
{
PyObject *first=NULL, *rest=NULL, *tmp;
static char *kwlist[] = {"first", "rest", NULL};
if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist,
&first, &rest))
return -1;
if (first){
tmp = self->first;
Py_INCREF(first);
self->first = first;
Py_XDECREF(tmp);
}
if (rest) {
tmp = self->rest;
Py_INCREF(rest);
self->rest = rest;
Py_XDECREF(tmp);
}
else {
tmp = self->rest;
Py_INCREF(Py_None);
self->rest = Py_None;
Py_XDECREF(tmp);
}
return 0;
}
static PyTypeObject PListType= {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"pysistence.persistent_list.PList", /*tp_name*/
sizeof(PList), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)PList_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
"Persistent list", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
plist_methods, /* tp_methods */
plist_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)PList_init, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
};
#ifndef PyMODINIT_FUNC
#define PyMODINIT_FUNC void
#endif
PyMODINIT_FUNC
initpersistent_list(void)
{
PyObject *m;
PListType.tp_new = PyType_GenericNew;
if (PyType_Ready(&PListType) < 0)
return;
m = Py_InitModule3("pysistence.persistent_list", 0,
"Docstring");
Py_INCREF(&PListType);
PyModule_AddObject(m, "PList", (PyObject*)&PListType);
}
如果我运行此代码,则会在最后一行显示段错误:
from pysistence.persistent_list import PList
p = PList(1)
p = PList(2, p)
p = p.cons(3)
我确定我只是在做一些愚蠢的事,但我不知道它是什么。有什么我想念的吗?
答案 0 :(得分:4)
我正在阅读文档:
PyObject* PyObject_CallFunctionObjArgs(PyObject *callable, ..., NULL)
Return value: New reference.
使用可变数量的PyObject *参数调用可调用的Python对象。参数以可变数量的参数提供,后跟NULL。返回成功时调用的结果,或失败时返回NULL。
你最后错过了NULL值。
编辑:Ho,您还想检查在内存发生故障时函数是否返回NULL