【问题标题】:Calling a C function with a double pointer output parameter using CGo使用 CGo 调用具有双指针输出参数的 C 函数
【发布时间】:2019-01-26 15:48:30
【问题描述】:

我正在尝试找出打电话给this function 的正确方法:

size_t
fz_buffer_storage(fz_context *ctx, fz_buffer *buf, unsigned char **datap)
{
    if (datap)
        *datap = (buf ? buf->data : NULL);
    return (buf ? buf->len : 0);
}

使用 CGo 获取底层字符串及其长度作为 Go 中的字节数组。

这是正确的做法吗?

var bufferContents *C.uchar
length := C.fz_buffer_storage(ctx, buf, &bufferContents)
bytes := C.GoBytes(unsafe.Pointer(bufferContents), C.int(length))

由于 C 代码覆盖了*datap,我不确定垃圾收集器是否仍然会做正确的事情。

我看到一个答案 here 提出了一些类似的建议

var tempUcharPtr *C.uchar
bufferContents := C.malloc(C.size_t(unsafe.Sizeof(tempUcharPtr)))
defer C.free(bufferContents)
length := C.fz_buffer_storage(ctx, buf, (**C.uchar)(bufferContents))
bytes := C.GoBytes(unsafe.Pointer(*(**C.uchar)(bufferContents)), C.int(length))

这似乎也有效,但它更令人费解,我想知道它是否比以前的版本更好/更安全。

【问题讨论】:

    标签: c pointers go garbage-collection cgo


    【解决方案1】:

    显然,第一个版本很好。引用the docs:

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

    据我了解,由于 var bufferContents *C.uchar 将被初始化为 nil,因此对于上述规则,它不算作“Go 指针”。以下简化的代码示例证实了这一点:

    package main
    
    // void F(char **p) {}
    import "C"
    
    func main() {
        var p *C.char = new(C.char)
        C.F(&p)
    }
    

    将触发“恐慌:运行时错误:cgo 参数的 Go 指针指向 Go 指针”

    package main
    
    // void F(char **p) {}
    import "C"
    
    func main() {
        var p *C.char
        C.F(&p)
    }
    

    工作正常,即使设置GODEBUG=cgocheck=2

    感谢 Gophers Slack 社区 #cgo 频道上的人们帮助我理解这一点!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-07-12
      • 2016-09-06
      • 2013-03-31
      • 2012-11-05
      • 1970-01-01
      • 1970-01-01
      • 2011-04-19
      相关资源
      最近更新 更多