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个:
- 不用bytes.Buffer
- 使用copy(dst,src)将值转入新的单个go变量
- C.f(pData)调用改成C.f(unsafe.Pointer(&data[0])),为什么这个可以,还需要深入研究下了。
这里推荐第2个或第3个解决方案,因为作为一个封装的库的话,永远也无法保证外面传的变量是什么样的。