【问题标题】:How can I fill out void* C pointer in Go?如何在 Go 中填写 void* C 指针?
【发布时间】:2016-06-26 06:02:49
【问题描述】:

我正在尝试与 Go 中的一些 C 代码进行交互。使用 cgo,这一直是相对简单的,直到我遇到这种(相当常见的)情况:需要将指针传递给本身包含指向某些数据的指针的结构。如果不求助于将结构的创建放入 C 代码本身,我似乎无法从 Go 中弄清楚如何做到这一点,我不想这样做。这是一个说明问题的sn-p:

package main

// typedef struct {
//     int   size;
//     void *data;
// } info;
//
// void test(info *infoPtr) {
//     // Do something here...
// }
import "C"

import "unsafe"

func main() {
    var data uint8 = 5
    info := &C.info{size: C.int(unsafe.Sizeof(data)), data: unsafe.Pointer(&data)}
    C.test(info)
}

虽然编译正常,但尝试运行它会导致:

panic: runtime error: cgo argument has Go pointer to Go pointer

在我的例子中,传递给 C 调用的数据不会在调用之后持续存在(即,有问题的 C 代码会深入到结构中,复制它需要的内容,然后返回)。

【问题讨论】:

    标签: go cgo


    【解决方案1】:

    参见cgo 文档中的"Passing pointers" 部分:

    Go 代码可以将 Go 指针传递给 C,前提是它指向的 Go 内存不包含任何 Go 指针。

    还有:

    这些规则在运行时动态检查。检查由 GODEBUG 环境变量的 cgocheck 设置控制。默认设置是 GODEBUG=cgocheck=1,它实现了相当便宜的动态检查。可以使用 GODEBUG=cgocheck=0 完全禁用这些检查。可以通过 GODEBUG=cgocheck=2 对指针处理进行完整检查,但需要在运行时付出一些代价。

    如果您运行您提供的 sn-p:

    GODEBUG=cgocheck=0 go run snippet.go
    

    那么就没有恐慌了。但是,正确的做法是使用C.malloc(或从其他地方获取“C 指针”):

    package main
    
    // #include <stdlib.h>
    // typedef struct {
    //     int   size;
    //     void *data;
    // } info;
    //
    // void test(info *infoPtr) {
    //     // Do something here...
    // }
    import "C"
    
    import "unsafe"
    
    func main() {
        var data uint8 = 5
    
        cdata := C.malloc(C.size_t(unsafe.Sizeof(data)))
        *(*C.char)(cdata) = C.char(data)
        defer C.free(cdata)
    
        info := &C.info{size: C.int(unsafe.Sizeof(data)), data: cdata}
        C.test(info)
    }
    

    它之所以有效,是因为虽然不允许使用常规 Go 指针,但 C.malloc 返回一个“C 指针”:

    Go 指针表示指向 Go 分配的内存的指针(例如通过使用 & 运算符或调用预定义的 new 函数),术语 C 指针表示指向 C 分配的内存的指针(例如通过调用 C.马尔洛克)。指针是 Go 指针还是 C 指针是由内存分配方式决定的动态属性。

    请注意,您需要包含stdlib.h 才能使用C.free

    【讨论】:

    • 谢谢。这就是我最终的结果......我只是希望能少一点冗长。
    • 有点切线,但有谁知道如何在vscode中设置GODEBUG?
    猜你喜欢
    • 2012-02-18
    • 2019-02-03
    • 2011-10-27
    • 2021-04-08
    • 1970-01-01
    • 2014-05-30
    • 2011-04-01
    相关资源
    最近更新 更多