使用ctypes访问C++类属性触发段错误,Valgrind下却正常
问题分析与解决思路
核心问题1:C++库编译链接方式错误
你用gcc链接C目标文件,但gcc不会自动链接C标准库(libstdc++),这会导致运行时C对象的构造、内存管理等操作出现未定义行为——编译能通过,但实际运行时依赖的C标准库符号无法正确解析,最终触发段错误。而Valgrind运行时可能通过特殊机制补全了依赖,所以能正常执行。
修复编译命令:
改用g++执行链接操作,它会自动处理C++标准库的依赖:
g++ -c -Wall -fPIC moncc.cc -o moncc.o g++ moncc.o -shared -o test.so
(注:编译阶段的-lstdc++是多余的,编译目标文件时无需链接库,g++在链接阶段会自动添加标准库依赖)
核心问题2:ctypes未指定函数类型信息
ctypes默认将C函数的返回值解析为int类型,但64位系统中指针是8字节,int仅为4字节,这会导致CreateTest()返回的test*指针被截断成无效的4字节地址。后续调用set_value或print时传入错误指针,直接触发段错误。Valgrind的内存检查机制可能对这种截断做了兼容,因此未暴露问题。
修复wrapper.py:
为每个导出的C函数指定正确的返回值与参数类型:
#!/usr/bin/env python # coding: utf-8 import ctypes lib = ctypes.CDLL("test.so") # 指定CreateTest返回类型为void*(对应C++的test*) lib.CreateTest.restype = ctypes.c_void_p # 指定set_value的参数类型:第一个是对象指针,第二个是int值 lib.set_value.argtypes = [ctypes.c_void_p, ctypes.c_int] # 指定print的参数类型:对象指针 lib.print.argtypes = [ctypes.c_void_p] class test(object): def __init__(self): self.obj = lib.CreateTest() def set_value(self,val): lib.set_value(self.obj,val) def print(self): lib.print(self.obj)
验证修复
修改后重新编译库,运行python3 main.py,即可正常输出:
Here1 Here2 valeur : 5
内容的提问来源于stack exchange,提问作者Julien B.
相关产品推荐
相关产品推荐

