3

在我的 Python 程序的 C 扩展中,我试图通过将主 C 函数的两个输入(称为数百万次)设置为全局变量来提高性能,因为它们不会经常更改,所以我不不必继续使用 lambda 包装器从 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 被分配给一个 128 个字符的数组,该数组在函数 splitchars_to_mapping 中进行了 malloc'ed,wordCmp 是一个传递给 C 的 Python 函数对象。无论如何,据我所知,char* splitArray 有效作为一个全局变量很好,但是当我后来尝试使用 PyEval_CallObject 调用 wordCmp 时,Python/C 崩溃了。所以我有两个问题:

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

1 回答 1

3

至于第一个问题,为什么在释放未初始化的全局变量时它不会崩溃,那是因为全局(和静态)变量被初始化为zero程序加载时(由标准保证)和调用时free()使用NULL(或零) 它什么也不做。

从人免费(1)

free(ptr) 之前已经被调用过,会发生未定义的行为。 如果 ptr 为 NULL,则不执行任何操作。

编辑:您的第二个问题与您尝试复制 aPyObject并且您不应该这样做的事实有关,因为该PyObject结构可能包含指针并且您无法进行深度复制,因为您无权访问该结构,但是,您应该增加引用计数并保留引用以供以后使用,请注意,当您使用时O,引用计数不会增加,来自文档

O (object) [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 回答