I'm trying to develop a routine in Go that will be called by a C++ program. The Go looks like the following:
package main
import (
"C"
"encoding/json"
"log"
)
type keydata struct {
Key string `json:"key"`
Error string `json:"Error"`
}
func lookupKey() string {
//simplified to remove the call to web service
body := "{\"key\": \"blahblah\", \"Error\": \"\"}"
k := keydata{}
err := json.Unmarshal([]byte(body), &k)
if err != nil {
log.Fatal(err)
}
return k.Key
}
//export GetKey
func GetKey() string {
theKey := lookupKey()
return theKey
}
func main() {}
If I substitute some hard coded value for the return k.Key statement everything works fine and the C or C++ can call the exported GetKey function. When I try to return the decoded JSON string from k.Key or even just return the string from the variable named body - I receive an error:
runtime error: cgo result has Go pointer goroutine 17 [running, locked to thread]
I'm building this as follows:
go build -buildmode=c-archive example.go
The C++ is built as follow:
g++ -pthread test.cpp example.a -o test
What am I missing to make this work without raising a panic error? I'm digging around to find an answer but have yet to resolve this.
@JimB & @Jsor, thank you so much for your responses. Returning a *C.char certainly worked. I'm left wondering though, when I return it as a Go string behind the scenes in the auto generated header file Go actually creates and passes a C struct named GoString that contains a char array named p and the length named n. As long as I pass a hard-coded string instead of k.Key it actually works and I can interrogate the auto-generated char array in C++. When I try to return k.Key, a string it throws that exception. Is it possible to cast the Go string or add some notation to the export decoration to make it work?
I can certainly return the C.CString char array and make it work - thank you! I'm just also wanting to understand why it works when returning a hard coded string and not in the example I've posted.
Thank you both for your time and explanations.
You can't return a Go string
to a C function. If you want a C string, you can use the C.CString
function to create one and return a *C.char
//export GetKey
func GetKey() *C.char {
theKey := lookupKey()
return C.CString(theKey)
}
The return value from this function must be explicitly freed in the C code.
If freeing the allocated buffer isn't convenient, its common to fill a buffer provided by the caller:
func GetKey(buff *C.char, n int) int
If you can allocate the memory but don't want to handle C strings, you can insert the buffer into a pointer and return the size.
func GetKey(buff **C.char) int
You need to use C.CString
to convert Go strings to raw pointers to C strings. Note that C Strings are not garbage collected and must be freed by you elsewhere in the program.
This will make the return type *C.char
which should be visible to C as a char
array. It will also be your responsibility to return the buffer length (whether your write a separate function or a C struct to do that is up to you).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.