1

First of all, cgo is pretty cool, thanks for that :)

I do have a question though, I have a lot of C structs that just contain a byte array, and I want to use the array in it as a []byte. ie:

typedef struct {
    unsigned char data[64];
} pubkey;

I would like to be able to then do:

type SchnorrPublicKey struct {
    pubkey C.pubkey
}

func (key *SchnorrPublicKey) String() string {
    return hex.EncodeToString(key.pubkey.data[:])
}

But I get the following error: ./schnorr.go:39:43: cannot use key.pubkey.data[:] (type []_Ctype_uchar) as type []byte in argument to hex.EncodeToString I can get this working by doing something like: return hex.EncodeToString(C.GoBytes(unsafe.Pointer(&key.pubkey.data[0]), C.int(len(key.pubkey.data))))

But it feels kinda stupid, it's a lot of complexity to convert an already go slice into another go slice just to replace the _Ctype_uchar type with byte type, and they are 100% compatible anyway.

Is there a better way to do this?

elichai2
  • 1,365
  • 3
  • 14
  • 28
  • Why do you have a `[]C.uchar` in the first place? The `_Ctype_uchar` isn’t much use in Go, and a slice isn’t much use in C. It seems it would be easier to not create a mixed type like this to start with. – JimB Mar 23 '20 at 02:24
  • It's the result of cgo auto-generating a C struct in go. the `unsigned char data[64];` array is represented in go as `[]_Ctype_uchar` – elichai2 Mar 23 '20 at 08:43
  • I doubt it's creating a `[]_Ctype_uchar`, otherwise you wouldn't need the `[:]` slice notation there. `GoBytes` is the correct function to use to copy the data into Go memory, or: https://stackoverflow.com/questions/28925179/cgo-how-to-pass-struct-array-from-c-to-go/, – JimB Mar 23 '20 at 12:46
  • This is also covered here: https://github.com/golang/go/wiki/cgo – JimB Mar 23 '20 at 12:55

1 Answers1

2

There is an open proposal for a function to do this in https://golang.org/issue/19367.

In the meantime, if you have a constant upper bound on the size of the slice (as, in this case, 64):

    var cPtr = &key.pubkey.data[0]
    const upperBound = 64
    var n = 64

    slice := (*[upperBound]byte)(unsafe.Pointer(cPtr))[:n:n]

and if you don't, see the function in https://github.com/golang/go/issues/13656#issuecomment-303216308.

bcmills
  • 4,391
  • 24
  • 34