Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

cgo how to set a C union value

Tags:

c

go

unions

cgo

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.

like image 203
Westy10101 Avatar asked Jan 19 '26 19:01

Westy10101


1 Answers

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.

like image 130
Ainar-G Avatar answered Jan 22 '26 10:01

Ainar-G



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!