CGo Passing Multidimensional Array

965 views
Skip to first unread message

pet...@ollins.email

unread,
Oct 31, 2014, 1:34:53 AM10/31/14
to golan...@googlegroups.com
My question is similar to the original question asked by this stackoverflow post.  Basically how would I be able to pass in a multiple dimensional byte ([][]byte) array such that it could be read by my C code.

The Go code compiles and runs, but crashes within the C code which just reads the array like below.  My C code is working, I'm just having trouble passing the pointer correctly.

Passing in a [][]byte multiple dimensional array into this C psuedocode function

void getMatrix(unsigned char **matrix) {
       
for (j = 0; j < srcs; j++) {
                for (i = 0; i < len; i++) {
                     s = src[j][i];
               
}
       
}
}

with this Go psuedocode

import "C"
import "unsafe"

func Hello() {
sources := make([][]byte, k)
for i := range sources {
sources[i] = make([]byte, sourceLength)
}
C.getMatrix((**C.uchar)(unsafe.Pointer(&sources[0])))
}


The problem I am having is casting the Go [][]byte array correctly to the C unsigned char** correctly. Any ideas? Can this be done? Would a single dimensional array be better?

egon

unread,
Oct 31, 2014, 4:55:30 AM10/31/14
to golan...@googlegroups.com
First take a look at how slices are stored internally: 

It should give you an idea why it doesn't work.

Yes, a single dimensional array would be better.

Essentially write your C function as:
getMatrix(unsigned char *matrix, int ncols, int nrows)

And keep the Go matrix in a single array []byte.

Also ensure that array doesn't get prematurely garbage collected.

sources := make([]byte, 100)
data := unsafe.Pointer(&sources[0])
C.getMatrix((*C.uchar)(data), 10, 10)
_ = data

I can't remember the exact rules how to properly pass pointers to C, but it probably is covered in some thread/page.

+ egon

Stephen Gutekanst

unread,
Oct 31, 2014, 4:57:07 AM10/31/14
to golan...@googlegroups.com
Perhaps without understanding why, the reason that you write:

unsafe.Pointer(&sources[0])

Is because slices have a slice header, you can see an effective slice header definition in Go's reflect package: http://golang.org/pkg/reflect/#SliceHeader

When you get a pointer to the first element in a slice, you're grabbing a pointer to the start of the slice's data.

Now, in your C code you are treating slices as if they are arrays: they are not. [][]byte and **uchar are two totally separate things.

A single dimensional array would simplify the problem, yes. Mainly you just need to acknowledge the slice header in your C code.

- Stephen

peterGo

unread,
Oct 31, 2014, 6:04:10 AM10/31/14
to golan...@googlegroups.com
Peter,

A multidimensional array is not the same as a multidimensional slice. Construct the multidimensional slice so that it uses a multidimensional array as its underlying array. For example,

Playground: http://play.golang.org/p/hbrh1iF1w_

Then you can write

    C.getMatrix((**C.uchar)(unsafe.Pointer(CMatrixPtr(matrix))))

Peter
Reply all
Reply to author
Forward
0 new messages