dtt83024 2016-05-24 15:28
浏览 228
已采纳

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

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.

  • 写回答

2条回答 默认 最新

  • duanlv2788 2016-05-24 15:51
    关注

    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
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 matlab有关常微分方程的问题求解决
  • ¥15 perl MISA分析p3_in脚本出错
  • ¥15 k8s部署jupyterlab,jupyterlab保存不了文件
  • ¥15 ubuntu虚拟机打包apk错误
  • ¥199 rust编程架构设计的方案 有偿
  • ¥15 回答4f系统的像差计算
  • ¥15 java如何提取出pdf里的文字?
  • ¥100 求三轴之间相互配合画圆以及直线的算法
  • ¥100 c语言,请帮蒟蒻写一个题的范例作参考
  • ¥15 名为“Product”的列已属于此 DataTable