如何将字符串从JSON返回到C调用者(Golang CGO)?

时间:2016-05-24 15:28:28

标签: go 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() {}

如果我用一些硬编码值替换返回k.Key语句,一切正常,C或C ++可以调用导出的GetKey函数。当我尝试从k.Key返回解码的JSON字符串,或者甚至只是从名为body的变量返回字符串时 - 我收到一个错误:

运行时错误:cgo结果有Go指针 goroutine 17 [正在运行,锁定线程]

我正在构建如下:

go build -buildmode = c-archive example.go

C ++的构建如下:

g ++ -pthread test.cpp example.a -o test

在没有引发恐慌错误的情况下,我缺少什么才能完成这项工作?我正在四处寻找答案,但尚未解决这个问题。

@JimB& @Jsor,非常感谢你的回复。返回* C.char肯定有效。我不知道,当我在自动生成的头文件中将其作为Go字符串返回后,Go实际创建并传递一个名为GoString的C结构,其中包含名为p的char数组和名为n的长度。只要我传递一个硬编码的字符串而不是k.Key它实际上可以工作,我可以在C ++中查询自动生成的char数组。当我尝试返回k.Key时,它会抛出异常。是否可以转换Go字符串或在导出装饰中添加一些符号以使其有效?

我当然可以返回C.CString char数组并让它工作 - 谢谢!我只是想了解为什么它在返回硬编码字符串时起作用而不是在我发布的示例中。

感谢您的时间和解释。

2 个答案:

答案 0 :(得分:4)

您无法将Go string返回给C函数。如果您想要C字符串,可以使用C.CString函数创建一个并返回*C.char

//export GetKey
func GetKey() *C.char {
    theKey := lookupKey()
    return C.CString(theKey)
}

此函数的返回值必须在C代码中显式释放。

如果释放分配的缓冲区不方便,则通常填充调用者提供的缓冲区:

func GetKey(buff *C.char, n int) int

如果您可以分配内存但不想处理C字符串,则可以将缓冲区插入指针并返回大小。

func GetKey(buff **C.char) int

答案 1 :(得分:3)

您需要使用C.CString将Go字符串转换为C字符串的原始指针。请注意,C字符串不是垃圾回收,必须由程序中的其他位置释放。

这将使返回类型*C.char对应于C char数组。返回缓冲区长度也是你的责任(无论你编写一个单独的函数还是一个C结构来做到这一点都取决于你)。