基于Cython实现C与Pytest接口:段错误排查及static变量测试
问题分析与解决方案
一、段错误原因排查与修复
核心问题点
- 结构体名拼写不匹配:xyz.h中函数声明的参数为
struct Struct_1(带下划线),但abc.h定义、test.c实现均使用struct Struct1(无下划线),导致函数声明与定义不匹配,触发未定义行为。 - 悬空指针问题:test.c中
static const volatile struct Struct1 *cfg保存了Cython栈变量config_struct的地址,当py_initialize执行完毕,栈变量被销毁,cfg变为无效指针,后续访问会引发段错误。 - Cython函数声明类型不匹配:h123.pxd中声明的
initialize函数缺少原C函数的const volatile修饰符,类型不匹配导致未定义行为。
修复步骤
修正xyz.h的结构体名:
#include "abc.h" // 把Struct_1改为Struct1,与定义一致 void initialize(const volatile struct Struct1 *config);解决悬空指针问题:修改test.c,将
cfg从指针改为结构体实例,拷贝传入的配置内容而非保存指针:struct Struct2 { uint64_t V_enable_output_threshold; // 其他成员保留 }; // 替换原指针为结构体实例,保存配置拷贝 static struct Struct1 cfg; static struct Struct2 state; void initialize(const volatile struct Struct1 *const config) { // 拷贝配置内容到本地static变量 cfg = *config; state.V_inp = 0u; state.P_inp = 0ull; state.P_out = 0ull; state.V_enable_output_threshold = ((uint64_t) cfg.V_enable_output) << 32u; }修正Cython的函数声明:在h123.pxd中补充
const volatile修饰,匹配原C函数:from libc.stdint cimport * cdef extern from "abc.h": cdef struct Struct1: uint32_t V_enable_output cdef extern from "xyz.h": // 添加const volatile修饰符 cdef void initialize(const volatile Struct1 *config)
二、获取static变量值并验证
static变量属于文件作用域,外部无法直接访问,需通过导出函数间接获取:
1. 修改C代码添加访问函数
- 在test.c中添加获取阈值的函数:
// 新增函数,返回static变量state的阈值 uint64_t get_V_enable_output_threshold(void) { return state.V_enable_output_threshold; } - 在xyz.h中声明该函数:
#include "abc.h" void initialize(const volatile struct Struct1 *config); // 新增函数声明 uint64_t get_V_enable_output_threshold(void);
2. 更新Cython接口
- 在h123.pxd中添加函数声明:
cdef extern from "xyz.h": cdef void initialize(const volatile Struct1 *config) // 新增函数声明 cdef uint64_t get_V_enable_output_threshold(void) - 在C123.pyx的Class1中添加Python可调用的方法:
cimport h123 from libc.stdint cimport * cdef struct Struct2: uint64_t V_disable_output_threshold cdef class Class1: def __init__(self): pass def py_initialize(self, config): cdef h123.Struct1 config_struct config_struct.V_enable_output = config['V_enable_output'] h123.initialize(&config_struct) # 新增方法,返回阈值 def get_enable_threshold(self): return h123.get_V_enable_output_threshold()
3. 更新Pytest测试用例
修改test_C123.py,验证阈值是否正确:
import pytest import pyximport import sys sys.path.append('/software/module') from C123 import Class1 access = Class1() def test_py_initialize(): config = { 'V_enable_output': 2000000 } access.py_initialize(config) # 计算预期值:2000000左移32位 expected_threshold = 2000000 << 32 assert access.get_enable_threshold() == expected_threshold
内容的提问来源于stack exchange,提问作者Wireshark
相关产品推荐
相关产品推荐

