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

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

cgo how to set a C union value

问题

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

  1. typedef struct val {
  2. char *var1;
  3. type type;
  4. union {
  5. char *binary_val;
  6. char *bits_val;
  7. bool bool_val;
  8. double decimal64_val;
  9. char *enum_val;
  10. char *identityref_val;
  11. char *instanceid_val;
  12. int8_t int8_val;
  13. int16_t int16_val;
  14. int32_t int32_val;
  15. int64_t int64_val;
  16. char *string_val;
  17. uint8_t uint8_val;
  18. uint16_t uint16_val;
  19. uint32_t uint32_val;
  20. uint64_t uint64_val;
  21. } data;
  22. } 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?

  1. typedef struct val {
  2. char *var1;
  3. type type;
  4. union {
  5. char *binary_val;
  6. char *bits_val;
  7. bool bool_val;
  8. double decimal64_val;
  9. char *enum_val;
  10. char *identityref_val;
  11. char *instanceid_val;
  12. int8_t int8_val;
  13. int16_t int16_val;
  14. int32_t int32_val;
  15. int64_t int64_val;
  16. char *string_val;
  17. uint8_t uint8_val;
  18. uint16_t uint16_val;
  19. uint32_t uint32_val;
  20. uint64_t uint64_val;
  21. } data;
  22. } 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来设置它们:

  1. v._type = 0
  2. binary.LittleEndian.PutUint16(v.data[:], 42)
  3. C.print_val(v)
  4. v._type = 1
  5. cstr := C.CString("hello world")
  6. defer C.free(unsafe.Pointer(cstr))
  7. binary.LittleEndian.PutUint64(v.data[:], uint64(uintptr(unsafe.Pointer(cstr))))
  8. C.print_val(v)

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

  1. int16: 42
  2. string: hello world

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

英文:

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

  1. v._type = 0
  2. binary.LittleEndian.PutUint16(v.data[:], 42)
  3. C.print_val(v)
  4. v._type = 1
  5. cstr := C.CString("hello world")
  6. defer C.free(unsafe.Pointer(cstr))
  7. binary.LittleEndian.PutUint64(v.data[:], uint64(uintptr(unsafe.Pointer(cstr))))
  8. C.print_val(v)

This (with an appropriate print_val function) prints:

  1. int16: 42
  2. 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:

确定