I'm trying to use the ccall
Julia function to use code written in C.
I know how to pass an array as an argument to a function that expects int *arg
. For example, trying to use this C function
void sum_one(int *arr, int len)
{
for (int i=0; i<len; i++){
arr[i]++;
}
}
this Julia code works
x = collect(Cint, 1:5)
ccall((:sum_one, "/path/to/mylib.so"), Void, (Ptr{Cint}, Cint), x, 5)
It doesn't seem to be so straight forward with C functions that expect a pointer to a pointer (int **arg
) to be used as a 2-dimensional matrix. Say this one
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;
}
}
}
Here, I needed to create an Array of Arrays so that the C code would accept it:
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)
But this structure structure is not very convenient from the Julia side.
int **arg
?I will try to answer you questions one by one:
Is there any other way to pass a 2-dimensional matrix to a C function that expects an argument of the type int **arg?
Yes. You have to add a method to julia's cconvert
function so that it does the conversion from Matrix{Cint}
to Ptr{Ptr{Cint}}
. So you define:
Base.cconvert(::Type{Ptr{Ptr{Cint}}},xx2::Matrix{Cint})=Ref{Ptr{Cint}}([Ref(xx2,i) for i=1:size(xx2,1):length(xx2)])
(see next question for explanation) and can afterwards directly pass your matrix to ccall:
xx2=zeros(Cint,5,6)
ccall((:fill_matrix, "mylib.so"),Void, (Ptr{Ptr{Cint}}, Cint, Cint), xx2, 6,5)
However, I would suggest to be very conservative in which cconvert methods you overwrite, because other julia code might expect the original behavior.
If not, how can you transform an already existing 2-dimensional array of Julia to the array of arrays structure of C?
The following should work: You generate an Array of pointers to every column of your matrix, so in 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)
Now the matrix xx2
is filled by the C function. Note that in julia v0.3 you have to replace Ref(xx2,i)
with pointer(xx2,i)
and the other way around?
I don't think this is generally possible. In order to construct a julia 2D array, the data must be in a contiguous block of memory. If you are REALLY confident this is the case you can do:
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)
Which returns the original matrix. Here, the last argument to pointer_to_array
determines, if Julia takes the ownership of the array and the data should be freed by Julia's gc.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With