【问题标题】:Calling a C function from Julia and passing a 2D array as a pointer of pointers as argument从 Julia 调用 C 函数并将 2D 数组作为指针的指针作为参数传递
【发布时间】:2015-10-07 22:03:03
【问题描述】:

背景

我正在尝试使用 ccall Julia 函数来使用用 C 编写的代码。 我知道如何将数组作为参数传递给需要int *arg 的函数。比如尝试使用这个C函数

void sum_one(int *arr, int len)
{
  for (int i=0; i<len; i++){
    arr[i]++;
  }
}

这个 Julia 代码有效

x = collect(Cint, 1:5)
ccall((:sum_one, "/path/to/mylib.so"), Void, (Ptr{Cint}, Cint), x, 5)

问题

对于期望将指向指针 (int **arg) 的指针用作二维矩阵的 C 函数,这似乎并不那么简单。说这个

void fill_matrix(int **arr, int row, int col)
{
  for (int i=0; i<row; i++){
    for (int j=0; j<col; j++){
      arr[i][j] = arr[i][j] + i + j*10;
    }
  }
}

在这里,我需要创建一个 Array of Arrays 以便 C 代码接受它:

xx = [zeros(Cint, 5) for i in 1:6]
ccall((:fill_matrix, "/path/to/mylib.so"),
       Void, (Ptr{Ptr{Cint}}, Cint, Cint), xx, 6,5)

但是这种结构结构从 Julia 方面来说不是很方便。

问题

  • 还有其他方法可以将二维矩阵传递给需要 int **arg 类型参数的 C 函数吗?
  • 如果不是,如何将已经存在的 Julia 的二维数组 转换为 C 的 数组数组 结构?
  • 反之亦然?

【问题讨论】:

    标签: c julia


    【解决方案1】:

    我会尽量一一回答你的问题:

    有没有其他方法可以将二维矩阵传递给需要 int **arg 类型参数的 C 函数?

    是的。您必须向 julia 的 cconvert 函数添加一个方法,以便它执行从 Matrix{Cint}Ptr{Ptr{Cint}} 的转换。所以你定义:

    Base.cconvert(::Type{Ptr{Ptr{Cint}}},xx2::Matrix{Cint})=Ref{Ptr{Cint}}([Ref(xx2,i) for i=1:size(xx2,1):length(xx2)])
    

    (请参阅下一个问题的解释),然后可以直接将您的矩阵传递给 ccall:

    xx2=zeros(Cint,5,6)
    ccall((:fill_matrix, "mylib.so"),Void, (Ptr{Ptr{Cint}}, Cint, Cint), xx2, 6,5)
    

    但是,我建议您在覆盖哪些 cconvert 方法时非常保守,因为其他 julia 代码可能会期望原始行为。

    如果不是,如何将已经存在的 Julia 二维数组转换为 C 的数组结构数组?

    以下应该有效:您生成一个指向矩阵每一列的指针数组,因此在 julia-0.4 中:

    xx2=zeros(Cint,5,6)
    refAr=[Ref(xx2,i) for i=1:size(xx2,1):length(xx2)]
    ccall((:fill_matrix, "mylib.so"),Void, (Ptr{Ptr{Cint}}, Cint, Cint), refAr, 6,5)
    

    现在矩阵xx2 由C 函数填充。请注意,在 julia v0.3 中,您必须将 Ref(xx2,i) 替换为 pointer(xx2,i)

    反过来呢?

    我认为这通常是不可能的。为了构造一个 julia 二维数组,数据必须在一个连续的内存块中。如果您真的有信心,您可以这样做:

    p=pointer(refAr)  # This is a Ptr{Ptr{Cint}} representing the int**
    aa=pointer_to_array(p,6,false)
    bb=pointer_to_array(aa[1],(5,6),false)
    

    返回原始矩阵。在这里,pointer_to_array 的最后一个参数决定了 Julia 是否拥有数组的所有权,并且数据应该由 Julia 的 gc 释放。

    【讨论】:

      【解决方案2】:

      我不喜欢 Julia,但 C 绝对允许你传递多维数组:

      void fill_matrix(int row, int col, int (*arr)[col]) {
        for (int i=0; i<row; i++){
          for (int j=0; j<col; j++){
            arr[i][j] = arr[i][j] + i + j*10;
          }
        }
      }
      
      //and the call of the function above:
      int width = 7, height = 5, matrix[height][width];
      fill_matrix(height, width, matrix);
      

      关键是,不涉及指针数组,表达式arr[i][j] 将根据用于声明arr 的数组指针类型计算为arr[i*col + j]。数据在内存中只是连续的。

      现在,我不知道 Julia 是否允许您与像这样采用数组指针参数的 C 函数进行交互,但您可以尝试找出答案。可能还需要交换数组索引,这取决于 Julia 是以列优先还是行优先顺序存储其矩阵。无论哪种情况,尝试都应该很容易发现。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-08-31
        • 2012-01-24
        • 2021-10-05
        • 2020-11-08
        • 1970-01-01
        • 2018-05-14
        • 2022-01-20
        相关资源
        最近更新 更多