Search code examples
cgocgo

How to convert C uint64_t to Cgo consistently across OS?


I am using some C library form Go, using cgo to handle the conversion.

I have a C header file that looks like:

#include <stdlib.h>

typedef struct {
   k uint64_t;
} params;

This structure is used from Go with code like:

package test

/*
#cgo CFLAGS: -g -Wall
#cgo LDFLAGS: -L. -lmylib -lm -ldl
#include "mylib.h"
*/
import "C"
func NewParams(k uint64) Paramets {
  return Params{
    k:     C.ulonglong(k),
  }
}

The code compiles fine on OS X with Apple clang version 12.0.0, but fails on Linux with clang version 7.1.0, yielding the following error:

cannot use _Ctype_ulonglong(k) (type _Ctype_ulonglong) as type _Ctype_ulong in field value

If I change the call to C.ulonglong to C.ulong, it works fine on linux but then fails on OS X.

How can I ensure the same code works on both platform?


Solution

  • Using go build -work I was able to confirm the issue stems from differences in mapping:

    • On the linux side, a C unit64_t gets mapped to a C.ulong
    • On the Mac side, it gets mapped to C.ulonglong

    Note that both C.ulong and C.ulonglong gets mapped to a go uint64 but using the Go type directly and removing the C.xxx(k) conversion fails.

    Solution is to use C.uint64_t(k) which makes it explicit the size of the type we are talking about. This is just fine because the C type is uin64_t anyways.