将 Go []byte 转换为 C *char

我有一个 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 here

addr := (*C.uchar)(unsafe.Pointer(&buf.Bytes()[0])) //convert buffers byte array to a C array

rc := C.the_function(addr, C.int(buf.Len())) //Fails here

它在调用 C 函数时失败,说:


panic: runtime error: cgo argument has Go pointer to Go pointer

C函数:


int the_function(const void *data, int nbytes);

我能够使以下内容工作,但将字节数组转换为字符串感觉不对。有一个更好的方法吗?这种方法是否有对数据产生副作用的风险?


addr := unsafe.Pointer(C.CString(string(buf.Bytes()[0]))

同样,这需要在引入更严格的 cgo 指针规则的 Go 1.6 下工作。


谢谢你。


温温酱
浏览 449回答 2
2回答

30秒到达战场

如果要使用第一种方法,则需要在函数调用参数之外创建切片,并避免临时分配的切片头或参数中的外部结构,因此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 arraycBuf := (*[1 << 30]byte)(p)copy(cBuf[:], b)rc = C.the_function(p, C.int(buf.Len()))但是对于后两种选择,不要忘记释放 malloc 的指针。

qq_遁去的一_1

您的程序崩溃是因为在 go1.6 中将指针传递给 C 的规则发生了变化(有关详细信息,请参阅https://tip.golang.org/doc/go1.6#cgo)。我不知道你的程序为什么会崩溃,所以我创建了 Go issue&nbsp;https://github.com/golang/go/issues/14546。但是不管这个问题的答案如何,我都不会使用内部位bytes.Buffer(就像你一样)直接传递给 cgo。该bytes.Buffer实现可以改变未来,你程序将启动破神秘。我只是将您需要的数据复制到任何合适的结构中,然后使用它传递给 cgo。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go