C-Python扩展中的Global PyObject *变量

时间:2012-11-05 18:35:20

标签: python c

在我的Python程序的C扩展中,我试图通过将主C函数的两个输入(称为数百万次)设置为全局变量来提高性能,因为它们不经常更改,所以我不需要使用lambda包装器向C函数继续从Python提供它们(浪费了大量的时间)。我的代码看起来像这样。首先,我将全局变量声明在文件的顶部:

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被分配给128个字符的数组,该数组在函数splitchars_to_mapping中被malloc化,而wordCmp是一个传递给C的Python函数对象。无论如何,据我所知,char * splitArray作为全局变量工作正常,但是当我稍后尝试使用PyEval_CallObject调用wordCmp时,Python / C崩溃了。所以我有两个问题:

  1. 当我尝试在函数开头释放未初始化的指针wordCmp和splitArray时,为什么C不会立即崩溃?
  2. 为什么我以后在将它正确存储在堆上并将其作为全局保存引用时无法调用wordCmp?

1 个答案:

答案 0 :(得分:3)

关于第一个问题,为什么在释放未初始化的全局变量时它不会崩溃,这是因为在加载程序时全局(和静态)变量被初始化为zeroguaranteed by the standard )当你用free()(或零)调用NULL时,它什么都不做。

来自人free(1)

  之前已经调用了

free(ptr),发生了未定义的行为。   如果ptr为NULL,则不执行任何操作。

修改: 您的第二个问题与您尝试复制PyObject并且不应该这样做有关,因为PyObject结构可能包含指针而您无法执行 deep < / em>复制,因为您无权访问该结构,但您应该增加引用计数并保留引用以供以后使用,请注意,当您使用O时,引用计数不< / em>从docs

递增
  

O(对象)[PyObject *]       在C对象指针中存储Python对象(不进行任何转换)。因此,C程序接收到的实际对象   通过。 对象的引用计数不会增加。

因此,您应自行增加引用,请参阅此example

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;
}