To convert a Go slice to C array is easy with unsafe.Slice. The problem is that the multi-dimensional C array is an array of pointers (*(*float64)) which cannot travel between the C/Go barrier.
In your example, you flatten your slice, and recreate the pointers in that one big slice. You could go on with that example, but from the Go side: 1. have a "flat" []float64 wihich is N*M 2. have the [][]float64 as subslices of that one big flattened []float64: flat[i*M:i*(M+1)] 3. send that flat slice to the C side with unsafe.Slice 4. have the C side implement the same subslicing: create a []*float64 array and have each point to the corredt &flat[i*M]. 5. profit Denis a következőt írta (2024. január 26., péntek, 1:18:59 UTC+1): > I am trying to pass 2d array from Go to some C function void foo(in > **float, out *double). Since I want to have wrapper for this C function, > I'd like that Go function has definition like func > FooWrapper([][]float32) []float64. The easiest but not efficient > implementation is allocating all memory through C that listed below: > > func FooWrapper(values [][]float32) []float64 { > totalObj := len(values) > totalParams := len(values[0]) > results := make([]float64, totalObj) > > ptrArrLength := uintptr(totalObj) * cPointerSize > paramArrLength := uintptr(totalParams) * cFloatSize > > ptr := C.malloc(C.size_t(ptrArrLength + > paramArrLength*uintptr(totalObj))) > defer C.free(ptr) > > ptrSlice := unsafe.Slice((**C.float)(ptr), totalObj) > for i, obj := range values { > paramArrPtr := (*C.float)(unsafe.Add(ptr, > ptrArrLength+uintptr(i)*paramArrLength)) > ptrSlice[i] = paramArrPtr > > paramSlice := unsafe.Slice(paramArrPtr, totalParams) > for j, param := range obj { > paramSlice[j] = (C.float)(param) > } > } > > C.foo((**C.float)(ptr), (*C.double)(&results[0])) > > return results > } > > Is that safe implementation? Can I pass pointer of result data? As far as > I know, this pointer will be pinned because it passed to C function. > > But I want to allocate less memory just reusing Go memory, I've learned > about runtime.Pinner that make pointer pinned until runtime.Pinner.Unpin() > invocation. > I tried to write another implementation using pinner: > > func FooWrapper(values [][]float32) []float64 { > length := len(values) > results := make([]float64, length) > > pinner := runtime.Pinner{} > defer pinner.Unpin() > > arr := (**C.float)(C.malloc(C.size_t(uintptr(length) * cPointerSize))) > defer C.free(unsafe.Pointer(arr)) > slice := unsafe.Slice(arr, length) > for i, v := range values { > pinner.Pin(&v[0]) > slice[i] = (*C.float)(&v[0]) > } > > C.foo(arr, (*C.double)(&results[0])) > > return results > } > > But, unfortunately, this code doesn't work > > runtime: pointer 0xc016ecbfc0 to unused region of span > span.base()=0xc016eca000 span.limit=0xc016ecbfa0 span.state=1 > fatal error: found bad pointer in Go heap (incorrect use of unsafe or cgo?) > > Do I use runtime.Pinner wrong (as far as I know, I can pin slice data)? Or > there is another error in this code. Are there some implementations for > passing 3d (4d and so on) array to C function except for allocatiing and > copying all data to C memory? > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/8068c8df-6290-45a2-a08f-569a062f045fn%40googlegroups.com.