如何设置 C 语言中的联合(union)值?

huangapple go评论88阅读模式
英文:

cgo how to set a C union value

问题

给定以下的C结构体,我可以使用不安全指针读取数据联合的值,但是我不知道如何设置联合值的数据。

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;

在C语言中,有没有一种方法可以在不创建辅助方法的情况下设置联合值?一个设置string_val的示例将非常完美。我知道Go语言将联合表示为具有最长类型的字节数组,并且该类型的长度设置为字节数组的长度。

英文:

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.

答案1

得分: 1

似乎cgo将联合值转换为字节数组。因此,您可以使用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)

这段代码(配合适当的print_val函数)会输出:

int16: 42
string: hello world

这种方法是不安全不可移植的,如果有更好的方法,我会很乐意学习。

英文:

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.

huangapple
  • 本文由 发表于 2016年9月6日 17:21:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/39345285.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定