在我的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崩溃了。所以我有两个问题:
答案 0 :(得分:3)
关于第一个问题,为什么在释放未初始化的全局变量时它不会崩溃,这是因为在加载程序时全局(和静态)变量被初始化为zero
(guaranteed 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;
}