Cython public函数被C代码调用时触发Segmentation fault段错误
问题根因
触发段错误的核心原因是C扩展模块初始化流程不完整:你仅调用了PyInit_public()创建模块对象,但没有将模块注册到Python运行时的模块表中,Cython生成的Qu()函数执行时依赖模块初始化阶段填充的全局上下文指针,上下文为空时直接访问空指针就会触发段错误。
另外两个隐藏的编译配置问题:
- 调用
cython生成C代码时没有显式指定language_level,默认值可能和你pxd里声明的Python3规则不匹配,埋下兼容隐患 - GCC链接参数不全,没有加
--embed参数拉取Python嵌入场景的完整链接选项,换个环境可能直接链接失败
修正方案
1. 修正C侧调用代码(public_c.c)
补全模块注册逻辑,增加初始化失败的基础判断:
#include <Python.h> #include "public.h" int main() { Py_Initialize(); // 初始化模块后必须注册到sys.modules,才会触发模块完整的初始化逻辑 PyObject* public_mod = PyInit_public(); if (!public_mod) { if (PyErr_Occurred()) PyErr_Print(); Py_Finalize(); return 1; } PyDict_SetItemString(PyImport_GetModuleDict(), "public", public_mod); Py_DECREF(public_mod); printf("Init\n"); Qu(); printf("Finalize\n"); Py_Finalize(); return 0; }
2. 修正编译脚本(compile.sh)
显式指定Cython的语言版本,调整链接参数:
#!/bin/bash # 显式指定Python3语法,避免默认值兼容问题 cython -3 public.pyx gcc -fPIC $(python3-config --cflags) -c public.c -o public.o gcc -fPIC $(python3-config --cflags) -c public_c.c -o public_c.o # 加--embed参数获取嵌入场景的完整链接选项,顺序符合GCC从左到右解析依赖的规则 gcc public_c.o public.o $(python3-config --embed --ldflags) -o public_c
验证结果
重新执行编译脚本后运行生成的public_c可执行文件,会按顺序输出如下内容,无段错误:
Init Qu! Finalize
补充说明:如果你的Cython版本较老,可能需要在调用
Qu()前额外执行一次PyImport_ImportModule("public")确保模块级代码执行完毕,新版本Cython在模块注册到sys.modules时就会自动完成这部分逻辑。
内容的提问来源于stack exchange,提问作者m0Ray
相关产品推荐
相关产品推荐

