如何 return 从 JSON 到 C 调用者(Golang CGO)的字符串?
How to return a string from JSON to a C caller (Golang CGO)?
我正在尝试在 Go 中开发一个将由 C++ 程序调用的例程。 Go 如下所示:
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() {}
如果我用一些硬编码值替换 return k.Key 语句,一切正常,C 或 C++ 可以调用导出的 GetKey 函数。当我尝试 return 来自 k.Key 的解码 JSON 字符串,甚至只是 return 来自名为 body 的变量的字符串时 - 我收到错误消息:
运行时错误:cgo 结果有 Go 指针
goroutine 17 [运行,锁定到线程]
我按如下方式构建:
go build -buildmode=c-archive example.go
C++ 构建如下:
g++ -pthread test.cpp example.a -o 测试
我缺少什么才能在不引发恐慌错误的情况下完成这项工作?我正在四处寻找答案,但尚未解决这个问题。
@JimB 和@Jsor,非常感谢您的回复。返回 *C.char 当然有效。不过,我想知道,当我 return 它作为自动生成的头文件中幕后的 Go 字符串时,Go 实际上创建并传递了一个名为 GoString 的 C 结构,其中包含一个名为 p 的字符数组和名为 n 的长度.只要我传递一个硬编码字符串而不是 k.Key 它就可以正常工作,我可以在 C++ 中查询自动生成的 char 数组。当我尝试 return k.Key 一个字符串时,它会抛出该异常。是否可以转换 Go 字符串或向导出装饰添加一些符号以使其工作?
我当然可以 return C.CString 字符数组并使其工作 - 谢谢!我也只是想了解为什么它在 return 硬编码字符串时有效,而不是在我发布的示例中。
谢谢你们的时间和解释。
您需要使用 C.CString
将 Go 字符串转换为指向 C 字符串的原始指针。请注意,C 字符串不会被垃圾回收,必须由您在程序的其他地方释放。
这将使 return 类型 *C.char
应该作为 char
数组对 C 可见。 return 缓冲区长度也是您的责任(是否编写单独的函数或 C 结构来执行此操作取决于您)。
您不能 return Go string
到 C 函数。如果你想要一个 C 字符串,你可以使用 C.CString
函数创建一个 return 一个 *C.char
//export GetKey
func GetKey() *C.char {
theKey := lookupKey()
return C.CString(theKey)
}
此函数 的 return 值必须 在 C 代码中显式释放。
如果释放分配的缓冲区不方便,通常填充调用者提供的缓冲区:
func GetKey(buff *C.char, n int) int
如果你可以分配内存但不想处理 C 字符串,你可以将缓冲区插入一个指针和 return 大小。
func GetKey(buff **C.char) int
我正在尝试在 Go 中开发一个将由 C++ 程序调用的例程。 Go 如下所示:
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() {}
如果我用一些硬编码值替换 return k.Key 语句,一切正常,C 或 C++ 可以调用导出的 GetKey 函数。当我尝试 return 来自 k.Key 的解码 JSON 字符串,甚至只是 return 来自名为 body 的变量的字符串时 - 我收到错误消息:
运行时错误:cgo 结果有 Go 指针 goroutine 17 [运行,锁定到线程]
我按如下方式构建:
go build -buildmode=c-archive example.go
C++ 构建如下:
g++ -pthread test.cpp example.a -o 测试
我缺少什么才能在不引发恐慌错误的情况下完成这项工作?我正在四处寻找答案,但尚未解决这个问题。
@JimB 和@Jsor,非常感谢您的回复。返回 *C.char 当然有效。不过,我想知道,当我 return 它作为自动生成的头文件中幕后的 Go 字符串时,Go 实际上创建并传递了一个名为 GoString 的 C 结构,其中包含一个名为 p 的字符数组和名为 n 的长度.只要我传递一个硬编码字符串而不是 k.Key 它就可以正常工作,我可以在 C++ 中查询自动生成的 char 数组。当我尝试 return k.Key 一个字符串时,它会抛出该异常。是否可以转换 Go 字符串或向导出装饰添加一些符号以使其工作?
我当然可以 return C.CString 字符数组并使其工作 - 谢谢!我也只是想了解为什么它在 return 硬编码字符串时有效,而不是在我发布的示例中。
谢谢你们的时间和解释。
您需要使用 C.CString
将 Go 字符串转换为指向 C 字符串的原始指针。请注意,C 字符串不会被垃圾回收,必须由您在程序的其他地方释放。
这将使 return 类型 *C.char
应该作为 char
数组对 C 可见。 return 缓冲区长度也是您的责任(是否编写单独的函数或 C 结构来执行此操作取决于您)。
您不能 return Go string
到 C 函数。如果你想要一个 C 字符串,你可以使用 C.CString
函数创建一个 return 一个 *C.char
//export GetKey
func GetKey() *C.char {
theKey := lookupKey()
return C.CString(theKey)
}
此函数 的 return 值必须 在 C 代码中显式释放。
如果释放分配的缓冲区不方便,通常填充调用者提供的缓冲区:
func GetKey(buff *C.char, n int) int
如果你可以分配内存但不想处理 C 字符串,你可以将缓冲区插入一个指针和 return 大小。
func GetKey(buff **C.char) int