为了账号安全,请及时绑定邮箱和手机立即绑定

将 Go []byte 转换为 C *char

将 Go []byte 转换为 C *char

Go
温温酱 2021-12-20 10:14:20
我有一个 byte.Buffer,我使用 binary.Write() 函数将数据打包。然后我需要将此字节数组发送到 C 函数。使用 Go 1.6 我没有成功解决这个问题。buf := new(bytes.Buffer) //create my buffer....binary.Write(buf, binary.LittleEndian, data) //write my data to buffer hereaddr := (*C.uchar)(unsafe.Pointer(&buf.Bytes()[0])) //convert buffers byte array to a C arrayrc := C.the_function(addr, C.int(buf.Len())) //Fails here它在调用 C 函数时失败,说:panic: runtime error: cgo argument has Go pointer to Go pointerC函数:int the_function(const void *data, int nbytes);我能够使以下内容工作,但将字节数组转换为字符串感觉不对。有一个更好的方法吗?这种方法是否有对数据产生副作用的风险?addr := unsafe.Pointer(C.CString(string(buf.Bytes()[0]))同样,这需要在引入更严格的 cgo 指针规则的 Go 1.6 下工作。谢谢你。
查看完整描述

2 回答

?
30秒到达战场

TA贡献1828条经验 获得超6个赞

如果要使用第一种方法,则需要在函数调用参数之外创建切片,并避免临时分配的切片头或参数中的外部结构,因此cgo检查不会将其视为存储在 Go 中的指针.


b := buf.Bytes()

rc := C.the_function(unsafe.Pointer(&b[0]), C.int(buf.Len()))

该C.CString方法将更安全,因为数据被复制到 C 缓冲区中,因此没有指向 Go 内存的指针,并且后面的切片bytes.Buffer不会被修改或超出范围。您需要转换整个字符串,而不仅仅是第一个字节。这种方法确实需要分配和复制两次,但是如果数据量很小,与 cgo 调用本身的开销相比,这可能不是问题。


str := buf.String()

p := unsafe.Pointer(C.CString(str))

defer C.free(p)

rc = C.the_function(p, C.int(len(str)))

如果该解决方案中不能接受数据的 2 个副本,则还有第三种选择,您可以自己分配 C 缓冲区,并将单个副本复制到该缓冲区中:


p := C.malloc(C.size_t(len(b)))

defer C.free(p)


// copy the data into the buffer, by converting it to a Go array

cBuf := (*[1 << 30]byte)(p)

copy(cBuf[:], b)

rc = C.the_function(p, C.int(buf.Len()))

但是对于后两种选择,不要忘记释放 malloc 的指针。


查看完整回答
反对 回复 2021-12-20
?
qq_遁去的一_1

TA贡献1725条经验 获得超8个赞

您的程序崩溃是因为在 go1.6 中将指针传递给 C 的规则发生了变化(有关详细信息,请参阅https://tip.golang.org/doc/go1.6#cgo)。

我不知道你的程序为什么会崩溃,所以我创建了 Go issue https://github.com/golang/go/issues/14546

但是不管这个问题的答案如何,我都不会使用内部位bytes.Buffer(就像你一样)直接传递给 cgo。该bytes.Buffer实现可以改变未来,你程序将启动破神秘。我只是将您需要的数据复制到任何合适的结构中,然后使用它传递给 cgo。


查看完整回答
反对 回复 2021-12-20
  • 2 回答
  • 0 关注
  • 448 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号