我试图找出正确的方法来调用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))

似乎也可以使用,但问题更加复杂,我想知道它是否比以前的版本更好/更安全。

最佳答案

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



据我了解,由于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 channel 上的人们帮助我理解了这一点!

关于使用CGo调用带有双指针输出参数的C函数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51932020/

10-10 17:01