将Go [] byte转换为C * char [英] Convert Go []byte to a C *char

查看:64
本文介绍了将Go [] byte转换为C * char的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个byte.Buffer,我使用binary.Write()函数打包了数据.然后,我需要将此字节数组发送到C函数.使用Go 1.6时,我并没有成功解决这个问题.

I have a byte.Buffer that I pack with data using the binary.Write() function. I then need to send this byte array to a C function. Using Go 1.6 I have not been successful at figuring this out.

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函数的行上失败:

It fails on the line calling the C function saying:

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

C函数:

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

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

I was able to get the following to work, but it felt wrong converting the byte array to a string. Is there a better way to do this? Does this method risk side effects to the data?

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

同样,这需要在Go 1.6下进行,后者引入了更严格的cgo指针规则.

Again this needs to work under Go 1.6 which introduced stricter cgo pointer rules.

谢谢.

推荐答案

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

If you want to use your first approach, you need to create the slice outside the function call arguments, and avoid the temporarily allocated slice header or the outer structure in the arguments, so the cgo checks don't see it as a pointer stored in Go.

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

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

The C.CString method will be safer, in that the data is copied into a C buffer, so there is no pointer to Go memory, and there's no chance the slice behind the bytes.Buffer will be modified or go out of scope. You will want to convert the whole string, not just the first byte. This methods does need to allocate and copy twice, however if the amount of data is small it's probably not a concern compared to the overhead of the cgo call itself.

str := buf.String()
p := unsafe.Pointer(C.CString(str))
defer C.free(p)
rc = C.the_function(p, C.int(len(str)))

如果该解决方案中不接受数据的2个副本,则存在第三个选项,您可以自己分配C缓冲区,然后将单个副本复制到该缓冲区中:

If the 2 copies of the data aren't acceptable in that solution, there is a third option where you malloc the C buffer yourself, and make a single copy into that buffer:

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的指针.

But with both of those latter options, don't forget to free the malloc'ed pointer.

这篇关于将Go [] byte转换为C * char的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆