10

I am using cgo in a project, and I want to export a function for use. Here's an example of what I want to achieve:

package csplit

import (
    "C"
    "strings"
)

//export Split
/* The Split function takes two C strings, the second of which represents
   a substring to split on, and returns an array of strings. Example:
       Split("1,2", ",") // gives ["1", "2"]
*/
func Split(original *C.char, split *C.char) []*C.char {
        goResult := strings.Split(C.GoString(original), C.GoString(split))
        cResult := make([]*C.char, len(goResult))

        for idx, substring := range goResult {
                cResult[idx] = C.CString(substring)
        }

        return cResult
}

The problem is that the return type is Go allocated data, and not moved into the C heap. This panics with: runtime error: cgo result has Go pointer

1ijk
  • 1,417
  • 2
  • 19
  • 31

1 Answers1

14

You're returning a Go slice which is allocated in Go, and is a different structure than a C array. You need to allocate an array in C:

//export Split
func Split(original *C.char, split *C.char) **C.char {
    goResult := strings.Split(C.GoString(original), C.GoString(split))
    cArray := C.malloc(C.size_t(len(goResult)) * C.size_t(unsafe.Sizeof(uintptr(0))))

    // convert the C array to a Go Array so we can index it
    a := (*[1<<30 - 1]*C.char)(cArray)

    for idx, substring := range goResult {
        a[idx] = C.CString(substring)
    }

    return (**C.char)(cArray)
}
JimB
  • 104,193
  • 13
  • 262
  • 255
  • ah, thank you. I believe that allocating the C array first may be the trick. (will accept once I test it out for my use case, or add more details to the question if necessary) – 1ijk Jan 05 '17 at 20:56
  • 2
    @haiqus: sorry, I made a mistake typing this out, and should have included a sizeof in the malloc (I was thinking `char` instead of `char*` which would have been obvious had I not omitted the sizeof). I revised it to show the proper malloc size. – JimB Jan 06 '17 at 17:27
  • I'm late to the party but what does `(*[1<<30 - 1]*C.char)` mean? – fbiville Apr 01 '21 at 12:40
  • 1
    @fbiville: https://stackoverflow.com/questions/48756732/what-does-1-30c-yourtype-do-exactly-in-cgo/48756785#48756785 – JimB Apr 01 '21 at 12:42