代码之家  ›  专栏  ›  技术社区  ›  Mihai Todor

使用CGo调用带有双指针输出参数的C函数

  •  2
  • Mihai Todor  · 技术社区  · 6 年前

    我正在想办法打电话给你 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))
    

    这看起来也很有效,但它要复杂得多,我想知道它是否比以前的版本更好/更安全。

    1 回复  |  直到 6 年前
        1
  •  2
  •   Mihai Todor    6 年前

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

    如果Go代码所指向的Go内存不包含任何Go指针,则Go代码可以将Go指针传递给C。

    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)
    }
    

    将触发“panic:runtime error:cgo参数具有Go pointer to Go pointer”

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

    工作很好,即使在设置 GODEBUG=cgocheck=2 .

    感谢地鼠懒散社区cgo频道的人帮助我理解了这一点!