在(gcc)go中的打包结构

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

Packed Structs in (gcc)go

问题

我有一些旧的C代码,其中使用了大量的紧凑结构。我正在研究使用Go作为这些代码的包装器,但是在传递或甚至编写这些结构的定义方面遇到了困难。

示例:

  1. import "unsafe";
  2. type AlignTest struct {
  3. c byte;
  4. y int16;
  5. z int16;
  6. q int32;
  7. }
  8. func main() {
  9. vr := new(AlignTest);
  10. fmt.Println(unsafe.Sizeof(*vr), "\n");
  11. }

返回的结果是12,而不是我希望的1+2+2+4 = 9,这是一个紧凑/非对齐的结构。

我知道我可以只创建一个字节数组并手动解析,但这似乎非常脆弱和容易出错...

英文:

I have some old C code that makes somewhat heavy use of packed structures. I'm looking into using Go as a wrapper for this code, but am having difficulty finding a way to pass or even write definitions for these structures.

Example:

  1. import "unsafe";
  2. type AlignTest struct {
  3. c byte;
  4. y int16;
  5. z int16;
  6. q int32;
  7. }
  8. func main() {
  9. vr := new(AlignTest);
  10. fmt.Println(unsafe.Sizeof(*vr), "\n");
  11. }

Returns 12 rather than the 1+2+2+4 = 9 that I would want with a packed/unaligned struct.

I know that I could just create a byte array and do the parsing manually, but that seems very brittle and error prone...

答案1

得分: 6

你可以尝试这样做。

  1. package main
  2. import (
  3. "encoding/binary"
  4. "bytes"
  5. "fmt"
  6. )
  7. type Unpacked struct {
  8. C byte
  9. Y int16
  10. Z int16
  11. Q int32
  12. }
  13. type Packed struct {
  14. B [9]byte
  15. }
  16. func main() {
  17. var u Unpacked
  18. var p Packed
  19. var buf = bytes.NewBuffer(make([]byte, 0, len(p.B)))
  20. // Unpacked to Packed
  21. u = Unpacked{1, 2, 3, 4}
  22. if err := binary.Write(buf, binary.BigEndian, &u); err != nil {
  23. fmt.Println(err)
  24. }
  25. if err := binary.Read(buf, binary.BigEndian, &p); err != nil {
  26. fmt.Println(err)
  27. }
  28. fmt.Println("u", u, "to", "p", p)
  29. // Packed to Unpacked
  30. p = Packed{[...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9}}
  31. if err := binary.Write(buf, binary.BigEndian, &p); err != nil {
  32. fmt.Println(err)
  33. }
  34. if err := binary.Read(buf, binary.BigEndian, &u); err != nil {
  35. fmt.Println(err)
  36. }
  37. fmt.Println("p", p, "to", "u", u)
  38. }

.

  1. 输出:
  2. u {1 2 3 4} to p {[1 0 2 0 3 0 0 0 4]}
  3. p {[1 2 3 4 5 6 7 8 9]} to u {1 515 1029 101124105}
英文:

You could try something like this.

  1. package main
  2. import (
  3. "encoding/binary"
  4. "bytes"
  5. "fmt"
  6. )
  7. type Unpacked struct {
  8. C byte
  9. Y int16
  10. Z int16
  11. Q int32
  12. }
  13. type Packed struct {
  14. B [9]byte
  15. }
  16. func main() {
  17. var u Unpacked
  18. var p Packed
  19. var buf = bytes.NewBuffer(make([]byte, 0, len(p.B)))
  20. // Unpacked to Packed
  21. u = Unpacked{1, 2, 3, 4}
  22. if err := binary.Write(buf, binary.BigEndian, &u); err != nil {
  23. fmt.Println(err)
  24. }
  25. if err := binary.Read(buf, binary.BigEndian, &p); err != nil {
  26. fmt.Println(err)
  27. }
  28. fmt.Println("u", u, "to", "p", p)
  29. // Packed to Unpacked
  30. p = Packed{[...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9}}
  31. if err := binary.Write(buf, binary.BigEndian, &p); err != nil {
  32. fmt.Println(err)
  33. }
  34. if err := binary.Read(buf, binary.BigEndian, &u); err != nil {
  35. fmt.Println(err)
  36. }
  37. fmt.Println("p", p, "to", "u", u)
  38. }

.

  1. Output:
  2. u {1 2 3 4} to p {[1 0 2 0 3 0 0 0 4]}
  3. p {[1 2 3 4 5 6 7 8 9]} to u {1 515 1029 101124105}

答案2

得分: 5

你可能需要重新考虑你的架构-尝试将二进制输入传递到C层,并使用现有的结构(你不会破坏你不改变的东西)。我假设结构体的打包看起来像这样:

#ifdef WINDOWS
#pragma pack(push)
#endif
#pragma pack(BYTEALIGNMENT) // 例如 "#pragma pack(1)" 或 "#pragma pack(8)"

//--- 一些打包的结构体

#ifdef WINDOWS
#pragma pack(pop)
#endif
#ifdef POSIX
#pragma pack()
#endif

所有底层或第三方库所做的就是将一些void或const char进行类型转换为这些结构体。所以如果可能的话,尝试将这些数据转发到C层(在那里你可以获得指针),并且不要暴露这些结构体。

英文:

You may want to rethink your architecture- try passing the binary input down to the C layer and use the existing structures (you won't break what you don't change). I'm assuming the structure packing looks something like this:

  1. #ifdef WINDOWS
  2. #pragma pack(push)
  3. #endif
  4. #pragma pack(BYTEALIGNMENT) // e.g. "#pragma pack(1)" or "#pragma pack(8)"
  5. //--- Some packed structs
  6. #ifdef WINDOWS
  7. #pragma pack(pop)
  8. #endif
  9. #ifdef POSIX
  10. #pragma pack()
  11. #endif

All the underlying or 3rd Party libs are then doing is taking some void* or const char* and typecasting it to these. So if possible, try forwarding that data into a C layer (where you can get pointers) and don't expose the structures at all.

答案3

得分: 2

没有办法告诉gccgo编译紧凑结构。我能想到的最好的解决方案是手动添加填充:

  1. type AlignTest struct {
  2. c byte
  3. _ [3]byte // 匿名填充
  4. y int16
  5. z int16
  6. q int32
  7. }
英文:

There's no way to tell gccgo to compile packed structures. The best solution I can think of is to manually add padding:

  1. type AlignTest struct {
  2. c byte
  3. _ [3]byte // anonymous padding
  4. y int16
  5. z int16
  6. q int32
  7. }

答案4

得分: 1

这是工作的代码:

  1. package main
  2. import "unsafe"
  3. import "fmt"
  4. /*
  5. struct test {
  6. char c;
  7. short i;
  8. short j;
  9. int k;
  10. } __attribute__((packed));
  11. */
  12. import "C"
  13. type AlignTest struct {
  14. c byte
  15. y int16
  16. z int16
  17. q int32
  18. }
  19. func main() {
  20. vr := new(AlignTest)
  21. v := new(C.struct_test)
  22. fmt.Println(unsafe.Sizeof(*vr), "\n")
  23. fmt.Println(unsafe.Sizeof(*v), "\n")
  24. }

输出:

  1. 12
  2. 9
英文:

This works:

  1. package main
  2. import "unsafe"
  3. import "fmt"
  4. /*
  5. struct test {
  6. char c;
  7. short i;
  8. short j;
  9. int k;
  10. } __attribute__((packed));
  11. */
  12. import "C"
  13. type AlignTest struct {
  14. c byte
  15. y int16
  16. z int16
  17. q int32
  18. }
  19. func main() {
  20. vr := new(AlignTest)
  21. v := new(C.struct_test)
  22. fmt.Println(unsafe.Sizeof(*vr), "\n")
  23. fmt.Println(unsafe.Sizeof(*v), "\n")
  24. }

Output:

  1. 12
  2. 9

huangapple
  • 本文由 发表于 2011年7月13日 06:54:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/6672205.html
匿名

发表评论

匿名网友

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

确定