Call C function from Julia and pass a 2D array as a pointer pointer as an argument

Background

I am 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) 

Problem

This doesn't seem to be so straightforward with C functions that expect a pointer to a pointer ( int **arg ) to be used as a two-dimensional matrix. Say it

 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 An array of arrays so that the C code accepted 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 on the part of Julia.

Question (s)

  • Is there any other way to pass a two-dimensional matrix to a C function that expects an argument of type int **arg ?
  • If not, how can you convert an already existing two-dimensional Julia array into an array of arrays of structure C?
  • and vice versa?
+6
source share
2 answers

I will try to answer your questions one by one:

Is there any other way to pass a two-dimensional matrix to a C function that expects an argument of type int ** arg?

Yes. You must add the method to the julia cconvert function so that it performs 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 the following question for an explanation), and after that you can 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 it is very conservative to use the cconvert methods that you overwrite, because other julia code might expect the original behavior.

If not, how can you convert an already existing two-dimensional Julia array into an array of arrays of structure C?

The following should work: you create an array of pointers to each 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 filled with function C. Note that in julia v0.3 you need to replace Ref(xx2,i) with pointer(xx2,i)

and vice versa?

I do not think that this is possible at all. To build a julia 2D array, the data must be in a contiguous block of memory. If you are REALLY sure that this is so, 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) 

Returns the original matrix. Here, the last argument pointer_to_array determines whether Julia will own the array and the data should be freed by Julia gc.

+1
source

I'm not in Julia, but C definitely allows you to pass multidimensional arrays:

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

The fact is that an array of pointers is not involved, the expression arr[i][j] will be evaluated as arr[i*col + j] due to the type of pointer to the array used to declare arr . Data is just contiguous in memory.

Now I don't know if Julia allows you to interact with a C function that takes an array pointer argument like this, but you can try to figure it out. It may also be necessary to exchange array indices, which depends on whether Julia stores its matrices in the first or first row order. In any case, it should be easy to find out by trying.

0
source

All Articles