You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 22:40:57