4

Given I have a C structure as below. I am able to read the data union values using unsafe pointers but am unable to work out how I can set the union value data?

 typedef struct val {
    char *var1;

    type type;

    union {
        char *binary_val;      
        char *bits_val;        
        bool bool_val;         
        double decimal64_val;  
        char *enum_val;        
        char *identityref_val; 
        char *instanceid_val;   
        int8_t int8_val;       
        int16_t int16_val;    
        int32_t int32_val;     
        int64_t int64_val;     
        char *string_val;   
        uint8_t uint8_val;      
        uint16_t uint16_val;   
        uint32_t uint32_val;   
        uint64_t uint64_val;   
    } data;
} val_t;

Is there a way without creating helper methods in C? An example of setting string_val would be perfect? I am aware that Go represents a union as a byte array with the longest type setting the length of the byte array.

Westy10101
  • 861
  • 2
  • 12
  • 25
  • 1
    Just as you can read the values with an `unsafe.Pointer`, you should also be able to write them. – fuz Sep 06 '16 at 11:20

1 Answers1

1

It seems that cgo turns the union values into byte arrays. As such, you can set them using encoding/binary:

v._type = 0
binary.LittleEndian.PutUint16(v.data[:], 42)
C.print_val(v)

v._type = 1
cstr := C.CString("hello world")
defer C.free(unsafe.Pointer(cstr))
binary.LittleEndian.PutUint64(v.data[:], uint64(uintptr(unsafe.Pointer(cstr))))
C.print_val(v)

This (with an appropriate print_val function) prints:

int16: 42
string: hello world

This is unsafe and non-portable though, so if anyone has a better way, I'll be glad to learn it.

Ainar-G
  • 34,563
  • 13
  • 93
  • 119
  • This is a bad idea because you introduce a dependency on endianness for no reason at all. – fuz Sep 06 '16 at 11:21
  • 1
    @FUZxxl As I wrote, I would like to know a better way to do this. If you have one, why not write an answer? – Ainar-G Sep 06 '16 at 12:02
  • 1
    There no reason you need to use encoding/binary to write the value here. You have the value and the address, just assign it. – JimB Sep 06 '16 at 14:34