Python ctypes调用C++接口返回字符串数组数据损坏问题排查
问题根因分析
- C++侧局部对象悬空指针
你在getStrings函数中使用auto strs = inst->getStrings();接收vector时,因为getStrings返回的是vector引用,不加&的情况下auto会推导为值类型,相当于生成了一个局部vector副本。你将该局部副本的data()指针作为返回值输出,函数执行结束后局部vector被销毁,对应内存空间被回收,你拿到的就是野指针,因此前几个元素出现数据损坏,未被覆盖的后几个元素暂时正常。 - Python ctypes未声明函数原型
ctypes默认将所有导出函数的返回值识别为int类型,在64位操作系统中,指针长度为8字节、int长度为4字节,会导致返回的指针地址被截断,也可能引发内存访问异常。
修复方案
1. 修复C++代码
将getStrings函数中的值接收改为引用接收,避免生成局部副本:
void getStrings(void* test_ptr, char*** strings, size_t* length) { auto inst = reinterpret_cast<Test *>(test_ptr); // 加&用引用接收,不拷贝vector auto& strs = inst->getStrings(); *strings = strs.data(); *length = strs.size(); }
额外建议:补充对应destroyTest的导出函数,主动释放Test实例避免内存泄漏。
2. 修复Python代码
加载动态库后主动声明导出函数的参数和返回值类型:
from ctypes import * lib = cdll.LoadLibrary("test.so") # 声明函数原型 lib.createTest.restype = c_void_p lib.getStrings.argtypes = [c_void_p, POINTER(POINTER(c_char_p)), POINTER(c_size_t)] test_ptr = lib.createTest() strs_arr = POINTER(c_char_p)() strs_len = c_size_t() lib.getStrings(test_ptr, byref(strs_arr), byref(strs_len)) for i in range(0, strs_len.value): print("var {}: data={}".format(i, strs_arr[i]))
验证效果
修改后重新编译动态库,运行Python代码即可正常输出全部字符串:
var 0: data=b'test1' var 1: data=b'test2' var 2: data=b'test3' var 3: data=b'test4'
内容的提问来源于stack exchange,提问作者Phoenixx
相关产品推荐
相关产品推荐

