从Julia调用C函数并将2D数组作为指针指针传递为参数

时间:2015-10-07 22:03:03

标签: c julia

背景

我正在尝试使用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)

问题

C函数似乎没那么直接,期望指向指针(int **arg)的指针被用作二维矩阵。说这个

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;
    }
  }
}

在这里,我需要创建一个数组数组,以便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)

但这种结构结构从朱莉娅那边不太方便。

问题

  • 有没有其他方法可以将二维矩阵传递给需要int **arg类型参数的C函数?
  • 如果没有,您如何将已存在的 2维Julia数组转换为数组结构C?
  • 反过来?

2 个答案:

答案 0 :(得分:3)

我会尽力逐一回答你的问题:

  

有没有其他方法可以将二维矩阵传递给需要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 2D数组,数据必须位于连续的内存块中。如果你真的有信心,你可以这样做:

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释放。

答案 1 :(得分:0)

我不是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[i*col + j]将被评估为arr。数据在内存中只是连续的。

现在,我不知道Julia是否允许您与采用这样的数组指针参数的C函数进行交互,但您可能会尝试查找。可能还需要交换数组索引,这取决于Julia是以列优先还是按行优先顺序存储其矩阵。在任何一种情况下,通过尝试都应该很容易找到。