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.

Reply via email to