how to read char * string from a c union in cgo?

46 Views Asked by At

I have a c union that stores my data as part of a value struct

union data_union {
  char *string_val;
  int8_t int8_val;
  int64_t int64_val;
  // so on
};

typedef enum {
  MY_STRING,
  MY_INT8,
  MY_INT64,
  // so on
} data_type;

struct value_struct {
  data_type type;
  data_union data;
} 

if I want to read an int8 value from c into go i use

int8_val := *(*C.int8_t)(unsafe.Pointer(&(cValue.data[0])))
goInt := int64(int8_val)

similarly for a int64 value

int64_val := *(*C.int64_t)(unsafe.Pointer(&(cValue.data[0])))
goInt := int64(int64_val)

how do i read a char * null terminated string ?

i am doing the following and I am getting garbage values

string_val := C.GoString((*C.char)(unsafe.Pointer(&(cValue.data[0]))))

I have tried to cast to single characters, but to no avail

    var cString []byte
    ptr := unsafe.Pointer(&(cValue.data[0]))

    for {
        char := *(*C.char)(ptr)
        if char == 0 {
            break
        }
        cString = append(cString, byte(char))
        ptr = unsafe.Pointer(uintptr(ptr) + unsafe.Sizeof(char))
    }

    goString := string(cString)

and I have tried to cast to unsafe.Slice, but honestly I don't get it, and it doesn't work

    cStringPtr := (*byte)(unsafe.Pointer(&(cValue.data[0])))
    cString := unsafe.Slice(cStringPtr, 0)

    // Convert the byte slice to a Go string
    goString := string(cString)

1

There are 1 best solutions below

0
Abrar Ahmed On

After a bit of tinkering I realized that I could just return a char * from a C function on the C side of things

char *get_value_str(struct value_struct *value) {
    return value->data.string_val;
}

and then the conversion on the go side is simple

    goString := C.GoString(C.get_value_str(cValue))

still looking for a better way though, since I have a lot of entries in my union and I don't want to pollute my go code with wrappers to wrappers in a project where the whole thing was a wrapper to a c api in the first place.