cgo argument has Go pointer to Go pointer

bytes.Buffer引起 cgo argument has Go pointer to Go pointer错误

先看代码:

函数

func f(data []byte){
    pData:=unsafe.Pointer(&data[0])
    //do something with cgo
    C.f(pData)
}

正确调用

buf:=[]byte("hello")
f(buf) 

错误调用

buf:=bytes.Buffer{}
buf.Write([]byte("hello"))
f(buf.bytes()) //关键在这里

为什么用bytes.Buffer就会报错呢?

因为Go调用C Code时,Go传递给C Code的Go指针所指的Go Memory中不能包含任何指向Go Memory的Pointer。
参考:https://segmentfault.com/a/1190000013590585

这句话的意思比较难懂,通俗将就是指针指向的内存要么是Go的普通变量,要么是C的结构体变量,不能是Go结构体变量。不过不急,可以先来看下bytes.Buffer的源码

...
type Buffer struct {
	buf      []byte 
	off      int   
	lastRead readOp 
	...
}
...
func (b *Buffer) Bytes() []byte { return b.buf[b.off:] } //重点在这里
...

可见,Buffer.Bytes()返回的是结构体里buf这个字段。所以上面调用的最后,data指向的内存都是Buffer结构体的一个field字段,所以违背了上述原则。

解决方案有3个:

  1. 不用bytes.Buffer
  2. 使用copy(dst,src)将值转入新的单个go变量
  3. C.f(pData)调用改成C.f(unsafe.Pointer(&data[0])),为什么这个可以,还需要深入研究下了。

这里推荐第2个或第3个解决方案,因为作为一个封装的库的话,永远也无法保证外面传的变量是什么样的。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据