I want to call a go function from C++ and return a string.
The function:
//export EditStr
func EditStr(a string) (ostr string) {
ostr = fmt.Sprintf("[["+a+"]]")
fmt.Println(">> " + ostr)
return
}
CGO seems happy to compile this and generates:
extern GoString EditStr(GoString a);
When calling the function from C++
auto res = EditStr(GoString{.p = "asdf", .n = 4});
My debug output works (so passing the string to go seems fine), but it fails when returning the string.
>> [[asdf]]
panic: runtime error: cgo result is unpinned Go pointer or points to unpinned Go pointer
The documentation (https://pkg.go.dev/cmd/cgo#hdr-C_references_to_Go) seems to imply GoString works for passing data into go but does not really say anything about returning it.
The example MyFunction2 seems to hint *C.char should be used to return strings, but CGO seems to be happy returning string directly.
Is this just a bug / missing warning / missing error in CGO or is there a way to return strings directly?
(I know I could use (int64, *C.char) as a return value, but it seems silly to manually return the values if there is the GoString struct seeming to be intended to package those values.)
The panic you're seeing is telling you that you're passing a Go pointer into C (as GoString.p), which will result in undefined behavior as Go's garbage collector may collect or relocate it before it's used. The GoString type isn't meant to be used from C. As mentioned in the documentation you linked:
Go functions that take arguments of type string may be called with the C type _GoString_, described above. The _GoString_ type will be automatically defined in the preamble. Note that there is no way for C code to create a value of this type; this is only useful for passing string values from Go to C and back to Go.
The purpose of that type is to call C functions from Go with a string argument, and allow those C functions to pass it directly to other Go functions.
If you want to pass a string into C, you'll need to place it into into memory allocated by C (using malloc() & co.), which is what C.CString() does for you.