【问题标题】:How to pass a 2d array returned in a C function to python using ctypes如何使用 ctypes 将 C 函数中返回的二维数组传递给 python
【发布时间】:2019-06-20 20:42:28
【问题描述】:

我有一个 C 函数返回一个二维数组(实际上是 double**),我想使用 ctypes 将此 double** 传递给 python。对此存在疑问,但数组是在参数列表中修改的,而不是使用函数的返回。这是我的代码(C 函数和相应的 python 包装器)

double** flux_function_2d(double *u, double gamma){

  double **F;
  double p, H;

  F = (double **)malloc(4*sizeof(double *));
  for (int i = 0; i < 4; i++)
    F[i] = (double *)malloc(2*sizeof(double));

  p = (gamma - 1.0) * (u[3] - 0.5 * (u[1]*u[1] + u[2]*u[2]) / u[0]);
  H = u[3] / u[0] + p / u[0];

  F[0][0] = u[1]; F[1][0] = u[1] * u[1] / u[0] + p;
  F[2][0] = u[1] * u[2] / u[0]; F[3][0] = u[1] * H;

  F[0][1] = u[2]; F[1][1] = u[2] * u[1] / u[0];
  F[2][1] = u[2] * u[2] / u[0] + p; F[3][1] = u[2] * H;

  return F;
}


def c_flux_function_2d(u, gamma):
    flux = np.ctypeslib.load_library("libs/flux.so", ".")
    flux.flux_function_2d.argtypes = [POINTER(c_double), c_double]
    flux.flux_function_2d.restype = POINTER(POINTER(c_double))
    F = flux.flux_function_2d(u.ctypes.data_as(POINTER(c_double)),
        c_double(gamma))
    F_arr = np.ctypeslib.as_array(F, shape=(4, 2))
    return F_arr

错误发生在 F_arr = np.ctypeslib.as_array(F, shape=(4, 2)) 这意味着 numpy 无法解析 ctypes 中指针的指针。

提前致谢!

【问题讨论】:

  • double** 不是二维数组。
  • A double** 是一个数组数组。在这个答案中使用这种方法可能更容易:stackoverflow.com/a/11385138/530160(定义一个带有多维数组的结构,并传递一个指向它的指针。)
  • @NickODell:它也不是一个数组数组。它是一个指针,恰好可以使用与数组数组相同的语法进行索引。所涉及的内存布局与数组数组完全不同。
  • “传递给python”是什么意思?您始终可以通过F_arr[i]][j] 访问 Python 中的数据。您想将其用作 numpy-array 吗?如果是,由于内存布局不同,您需要将数据复制到 numpy 数组中。
  • 您打算如何释放返回的内存?修改作为参数传递的数组意味着 Python 管理内存,您不必处理释放 C 函数中分配的内存。

标签: python c ctypes


【解决方案1】:

如果你实际上有一个二维数组,你可以调用numpy.ctypeslib.as_array,但你没有

你有一个指向数组的第一个元素的指针,该指针指向其他数组的第一个元素。这与二维数组完全不同,它恰好可以在 C 中使用相同的语法进行索引。

你所拥有的内存布局与 NumPy 完全不兼容。 NumPy 数组有一个内存缓冲区,其中包含形状和步幅信息,告诉您在每个维度中可以走多远以及在每个维度中迈出一步需要走多少字节。

对于 C 连续数组(最常见的情况),MxN 数组缓冲区的内存布局与 C whatevertype[M][N] 相同。相反,您的数据结构的子数组分散在任意内存位置,在第一维中没有步幅这样的东西。

您需要将数据放入 NumPy 可以使用的布局中。有多种方法可以做到这一点,包括在 C 函数中分配和使用连续缓冲区,或创建 numpy.empty([4, 2]) 并使用嵌套循环将数据复制到其中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-10
    相关资源
    最近更新 更多