Passing 2D Julia arrays to C functions

560 views
Skip to first unread message

Ben Postlethwaite

unread,
Sep 12, 2013, 3:04:56 PM9/12/13
to julia...@googlegroups.com
If I have a C function that requires a 2D array

void printArray(double **x, int n, int m) {
  loop i
     loop j
       printf("2.2f\n", x[i][j]);
}


How would the array need to be passed in to ccall?

Julia:
n = 2
m = 2

x = Array(Any, (n, m))

for i = 1:n
  x[i, :] = rand( 1, m)
end

ccall((:printArray, "./libtest.so"), Void, ( Ptr{Float64}, Int32, Int32), x, int32(n), int32(m))

Doesn't work. The C func prints zeros... its not getting the types correctly.

any suggestions?

Jacob Quinn

unread,
Sep 12, 2013, 3:16:50 PM9/12/13
to julia...@googlegroups.com
Just create 'x' as a normal Float64 2D array.

x = randn(n,m)

And then pass as you're passing it now.

-Jacob

Ben Postlethwaite

unread,
Sep 12, 2013, 3:28:02 PM9/12/13
to julia...@googlegroups.com
That was my initial attempt, but it throws seg faults.

Ben Postlethwaite

unread,
Sep 12, 2013, 3:30:41 PM9/12/13
to julia...@googlegroups.com
Here is the exact code:

extern "C"
void get2darray(double **x, int n, int m) {

  int i, j;
  for (i = 0; i < n; i++) {
    for (j = 0; j < m; j++) {
      printf("%2.2f ", x[i][j]);
    }
    printf("\n");
  }
}


Julia:
n = 2
m = 2

x = rand(n, m)

ccall((:get2darray, "../deps/libsvm-test.so"), Void,
      ( Ptr{Float64}, Int32, Int32),
      x, int32(n), int32(m))

Sam Kaplan

unread,
Sep 12, 2013, 4:25:36 PM9/12/13
to julia...@googlegroups.com
Does this work? :

extern "C"
void get2darray(double *x, int n, int m) {

  int i;
  for (i = 0; i < m * n; i++) {
      printf("%2.2f ", x[i]);
  }
}

Ben Postlethwaite

unread,
Sep 12, 2013, 4:40:23 PM9/12/13
to julia...@googlegroups.com
Yes that works Sam. It is a great solution if I have control over the C functions, but if I don't and the C function is expecting a 2D array and indexes it with dual indices than this won't help. I suppose I could write a C shim that transforms the array appropriately before calling the final function. If multidimensional Julia arrays are laid out differently than C arrays, perhaps this is the only option? Luckily I have the source, so for this use case I can make a few changes and the method will work, thanks!

Kurt Franke

unread,
Sep 12, 2013, 4:46:02 PM9/12/13
to julia...@googlegroups.com
Hello Ben,

the double** is an array of pointers to pointers to doubles.
(btw, You might need to have %lf instead of %f in the printf...)

julia> a1 = [1.,2.]; a2 = [3.,4.];
julia> a = [pointer(a1,1),pointer(a2,1)];
julia> ccall((:get2darray, "test.dylib"),Void,(Ptr{Ptr{Float64}},Int32,Int32),pointer(a,1),int64(2),int64(2))
1.00 2.00 
3.00 4.00 

Kind regards,
Kurt

Kurt Franke

unread,
Sep 12, 2013, 4:49:42 PM9/12/13
to julia...@googlegroups.com
I didn't say that correctly..
the value stored in the double** is the address of the first element of an array of pointers,
and each of those pointers is the address of the first element of an array of doubles

This is different than a c array where the dimensions are known at compile time...

Ben Postlethwaite

unread,
Sep 12, 2013, 6:38:11 PM9/12/13
to julia...@googlegroups.com
Thanks Kurt! This will work with a little modification for large arrays a.
Reply all
Reply to author
Forward
0 new messages