dtwy2858 2016-02-27 17:42
浏览 739
已采纳

将Go [] byte转换为C * char

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

It fails on the line calling the C function saying:

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

The C function:

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]))

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

Thank you.

  • 写回答

2条回答 默认 最新

  • dpprx26000 2016-02-27 20:48
    关注

    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()))
    

    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)))
    

    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()))
    

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

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 求解 yolo算法问题
  • ¥15 虚拟机打包apk出现错误
  • ¥30 最小化遗憾贪心算法上界
  • ¥15 用visual studi code完成html页面
  • ¥15 聚类分析或者python进行数据分析
  • ¥15 三菱伺服电机按启动按钮有使能但不动作
  • ¥15 js,页面2返回页面1时定位进入的设备
  • ¥50 导入文件到网吧的电脑并且在重启之后不会被恢复
  • ¥15 (希望可以解决问题)ma和mb文件无法正常打开,打开后是空白,但是有正常内存占用,但可以在打开Maya应用程序后打开场景ma和mb格式。
  • ¥20 ML307A在使用AT命令连接EMQX平台的MQTT时被拒绝