6

How do I convert this C (array) type:

char my_buf[BUF_SIZE];

to this Go (array) type:

type buffer [C.BUF_SIZE]byte

? Trying to do an interface conversion gives me this error:

cannot convert (*_Cvar_my_buf) (type [1024]C.char) to type [1024]byte
Attila O.
  • 15,659
  • 11
  • 54
  • 84

2 Answers2

9

The easiest and safest way is to copy it to a slice, not specifically to [1024]byte

mySlice := C.GoBytes(unsafe.Pointer(&C.my_buff), C.BUFF_SIZE)

To use the memory directly without a copy, you can "cast" it through an unsafe.Pointer.

mySlice := (*[1 << 30]byte)(unsafe.Pointer(&C.my_buf))[:int(C.BUFF_SIZE):int(C.BUFF_SIZE)]
// or for an array if BUFF_SIZE is a constant
myArray := *(*[C.BUFF_SIZE]byte)(unsafe.Pointer(&C.my_buf))
JimB
  • 104,193
  • 13
  • 262
  • 255
  • I specifically want an array, not a slice. One of the reasons is that I do want to make a copy. Also, `C.BUF_SIZE` *is* a constant, so I can use it in a typedef. Also, why convert it to a pointer to a huge array? – Attila O. Dec 17 '14 at 19:19
  • 2
    The huge array is just so that the go compiler will accept any valid size, but it's not actually allocated (see some other examples here https://github.com/golang/go/wiki/cgo). – JimB Dec 17 '14 at 19:21
2

To create a Go slice with the contents of C.my_buf:

arr := C.GoBytes(unsafe.Pointer(&C.my_buf), C.BUF_SIZE)

To create a Go array...

var arr [C.BUF_SIZE]byte
copy(arr[:], C.GoBytes(unsafe.Pointer(&C.my_buf), C.BUF_SIZE))
tidwall
  • 6,881
  • 2
  • 36
  • 47
  • 1
    @JimB The second example seems to work for me. Here's an example https://play.golang.org/p/O49FFSyHCG (test locally) What error do you get? I'm running go1.4 on a Mac. – tidwall Dec 17 '14 at 19:10
  • Ah, I never checked to see if cgo treated `DEFINE` as a constant. That does work in this case. – JimB Dec 17 '14 at 19:18
  • 1
    FYI, the second example copies the data twice. – JimB Dec 17 '14 at 19:24
  • @JimB where is the first copy? I assume the second one is done by the actual `copy` built-in. And @tidwall, why take the address of `C.by_buf[0]`? Isn't that the same as taking the address of `C.my_buf`? – Attila O. Dec 17 '14 at 19:26
  • @AttilaO. `C.GoBytes` makes a copy of the data into a new slice. – JimB Dec 17 '14 at 19:28
  • @JimB Oh. I was under the impression that `C.GoBytes` will return a `[]byte` that points to the underlying C array. I see now that it does indeed make a copy. – Attila O. Dec 17 '14 at 19:31
  • @AttilaO. There is no difference. – tidwall Dec 17 '14 at 19:32