Python自定义C模块导入报错:Undefined Symbol问题求助
解决Python自定义C模块导入时的
undefined symbol: strrev错误 问题根源
1. strrev并非标准C函数
strrev是微软Visual C++专属的非标准字符串反转函数,Linux系统的glibc标准库中没有实现该函数。这就是编译时无报错,但导入模块时提示符号未定义的核心原因——链接阶段无法找到该函数的实现。
2. Python对象操作逻辑错误
代码中PyObject *ret = strrev(*name);存在严重错误:
name是指向Python Unicode对象的指针,直接解引用*name得到的是PyObject结构体,并非可直接操作的C字符串,无法传给strrev使用。- 即便
strrev存在,这种写法也会触发内存错误或程序崩溃。
解决步骤
步骤1:实现跨平台的字符串反转函数
自行编写标准C的字符串反转函数替代非标准的strrev:
char* my_strrev(char *str) { if (str == NULL) return NULL; char *start = str; char *end = start + strlen(str) - 1; char temp; while (start < end) { temp = *start; *start = *end; *end = temp; start++; end--; } return str; }
步骤2:正确处理Python Unicode对象
使用Python C API完成Python对象与C字符串的转换,严格遵循内存管理规则:
- 用
PyUnicode_AsUTF8AndSize将Unicode对象转为只读C字符串 - 分配内存复制该字符串(原字符串不可修改)
- 反转字符串后转回Python Unicode对象
- 释放临时分配的内存,避免泄漏
修正后的_strrev.c代码
#include <Python.h> #include <string.h> #include <stdlib.h> // 自定义跨平台字符串反转函数 char* my_strrev(char *str) { if (str == NULL) return NULL; char *start = str; char *end = start + strlen(str) - 1; char temp; while (start < end) { temp = *start; *start = *end; *end = temp; start++; end--; } return str; } static PyObject* _strrev(PyObject* self, PyObject *args) { PyObject* name; if (!PyArg_ParseTuple(args, "U", &name)) { return NULL; } // 将Python Unicode转为只读C字符串 const char *c_str = PyUnicode_AsUTF8AndSize(name, NULL); if (c_str == NULL) { return NULL; } // 分配内存复制字符串(原字符串只读,不可直接修改) char *temp_str = malloc(strlen(c_str) + 1); if (temp_str == NULL) { PyErr_SetString(PyExc_MemoryError, "Failed to allocate memory"); return NULL; } strcpy(temp_str, c_str); // 反转字符串 my_strrev(temp_str); // 将反转后的C字符串转回Python Unicode对象 PyObject *ret = PyUnicode_FromString(temp_str); // 释放临时内存 free(temp_str); return ret; } static struct PyMethodDef methods[] = { {"strrev", (PyCFunction)_strrev, METH_VARARGS}, {NULL, NULL} }; static struct PyModuleDef module = { PyModuleDef_HEAD_INIT, "_strrev", NULL, -1, methods }; PyMODINIT_FUNC PyInit__strrev(void) { return PyModule_Create(&module); }
步骤3:编译并验证
使用原setup.py(或替换为setuptools版本,与_hello模块一致)编译:
python setup.py build_ext --inplace
测试修复后的模块:
>>> import _strrev >>> _strrev.strrev("hello") 'olleh'
额外注意事项
- 禁止直接解引用
PyObject*指针,必须通过Python C API操作Python对象。 - 手动分配的C内存必须主动释放,避免内存泄漏。
- 避免使用非标准C函数,确保代码跨平台兼容性。
内容的提问来源于stack exchange,提问作者thanksforthehelp
相关产品推荐
相关产品推荐

