Python通过ctypes调用C++ DLL传递矩阵数据全为零问题排查
问题:Python向C++ DLL传递矩阵数据后全为零的解决
我需要实现Python与C++ DLL之间的矩阵数据交互:在Python中创建(c_double * 102)数组(数组前两位存储矩阵尺寸),Python端验证数据正确,但调用DLL填充矩阵时,矩阵始终被填充为全零。
Python代码
我实现了tu_matrix类用于将二维列表转为(c_types * 102)(0)类型数组,用指针传输数据:
class tu_matrix: body = (c_double * 102)(c_double(0)) ptr = POINTER(c_double * 102) def load(self, data = list(list())): self.data = data self.n_size = len(data) self.m_size = len(data[0]) for i in range(self.n_size): for j in range(self.m_size): self.body[2+i*self.m_size + j] = c_double(data[i][j]) ptr = pointer(self.body) def calcMatrix(): tu_matrix1.load(matrix1) tu_matrix2.load(matrix2) # 设置matrix_sum的参数类型 matrix_lib.matrix_sum.argtypes = [POINTER(c_double * 102), POINTER(c_double * 102)] # 设置matrix_sum的返回类型 matrix_lib.matrix_sum.restype = POINTER(c_double * 102) # 获取数组指针 ptr1 = pointer(tu_matrix1.send()) # 第一个数组指针 ptr2 = pointer(tu_matrix2.send()) # 第二个数组指针 # 调用DLL函数 result_ptr = matrix_lib.matrix_sum(ptr1, ptr2) result_array = result_ptr.contents # 获取指针指向的内容 # 转换为二维列表 list_of_lists = [] for i in range(0, 102, 10): sublist = [result_array[i + j] for j in range(10) if i + j < 102] list_of_lists.append(sublist) print(list_of_lists) return result_ptr
C++数据转换函数
尝试将Python传入的数据填充到vector中,但获取的数据全为零,怀疑问题出在自定义类(简单数组/数据类型能正常工作):
template<typename val_type> void matrix<val_type>::arr_to_matrix(double arr[102]) { this->body.clear(); for (int i = 0; i < (int)arr[0]; i++) { vector<double> line; for (int j = 0; j < (int)arr[1]; j++) { line.push_back(arr[2 + i * (int)arr[1] + j]); } this->body.push_back(line); } this->size_n = (int)arr[0]; this->size_m = (int)arr[1]; this->empty_matrix = false; this->zero_matrix = false; this->was_calc_det = false; }
C++ DLL函数
static double result[102]; extern "C" __declspec(dllexport) double* matrix_sum(double arr1[102], double arr2[102]) { // Python C-types数据的矩阵求和 matrix<double> m1({ { 1,1 }, { 2,2 } }); matrix<double> m2({ { 1,1 }, { 2,2 } }); m1.arr_to_matrix(arr1); m2.arr_to_matrix(arr2); m1 += m2; int n = m1.line_size(); int m = m1.column_size(); result[0] = n; result[1] = m; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { result[2 + i * m + j] = m1.val(i, j); } } return result; }
补充测试情况
- 删除
m1.arr_to_matrix(arr1); m2.arr_to_matrix(arr2);,直接用初始化列表初始化matrix时功能正常,但无法实现Python交互。 - 脱离Python单独运行C++代码时功能正常:
int main () { double* arr1 = new double[102]; double* arr2 = new double[102]; for (int i=0; i<6; i++) { arr1[i] = 2; arr2[i] = 2; } arr1 = matrix_sum(arr1, arr2); for (int i = 0; i<6; i++) { std::cout << arr1[i] << " "; } }
问题根源与修复方案
1. Python端tu_matrix类的核心错误
问题点:
body是类静态变量,所有实例共享同一个数组,易导致数据覆盖;load方法中仅在内部定义ptr,未赋值给实例属性,send()方法无法返回有效指针;- 未将矩阵尺寸写入数组前两位,C++端读取的尺寸为0,循环不执行导致矩阵全零。
修复后的
tu_matrix类:
class tu_matrix: def __init__(self): # 每个实例独立拥有数组,避免共享冲突 self.body = (c_double * 102)(0.0) self.ptr = None def load(self, data): self.data = data self.n_size = len(data) self.m_size = len(data[0]) # 写入矩阵尺寸到数组前两位 self.body[0] = self.n_size self.body[1] = self.m_size # 填充矩阵数据 for i in range(self.n_size): for j in range(self.m_size): self.body[2 + i * self.m_size + j] = data[i][j] self.ptr = pointer(self.body) def send(self): return self.body
2. 函数参数类型不匹配
问题点:
Python声明的argtypes为POINTER(c_double * 102),但C++函数实际接收的是double*(数组参数会退化为指针),类型不匹配导致数据传递异常。修复方案:
修改Python端参数类型声明为POINTER(c_double),直接传递数组对象(ctypes会自动转换为指针):
# 修改argtypes为正确的指针类型 matrix_lib.matrix_sum.argtypes = [POINTER(c_double), POINTER(c_double)] # 调用时直接传入数组本体 result_ptr = matrix_lib.matrix_sum(tu_matrix1.body, tu_matrix2.body)
3. DLL静态数组的线程安全优化(可选)
当前DLL使用static double result[102],多线程调用会出现数据覆盖。建议改为动态分配内存,由Python端负责释放:
extern "C" __declspec(dllexport) double* matrix_sum(double arr1[102], double arr2[102]) { // 动态分配内存,避免静态数组的线程安全问题 double* result = new double[102]; // ... 原有求和逻辑 ... return result; }
Python端使用后手动释放内存:
from ctypes import free # 调用完成后释放内存 free(result_ptr)
内容的提问来源于stack exchange,提问作者Fedor Polushkin
相关产品推荐
相关产品推荐

