包装结构(gcc)去

我有一些旧的C代码,有点大量使用打包结构。 我正在考虑使用Go作为此代码的包装器,但是很难找到传递或甚至为这些结构编写定义的方法。

例:

import "unsafe"; type AlignTest struct { c byte; y int16; z int16; q int32; } func main() { vr := new(AlignTest); fmt.Println(unsafe.Sizeof(*vr), "\n"); } 

使用打包/未对齐的结构返回12而不是1 + 2 + 2 + 4 = 9。

我知道我可以创建一个字节数组并手动进行解析,但这看起来非常脆弱且容易出错……

你可以尝试这样的事情。

 package main import ( "encoding/binary" "bytes" "fmt" ) type Unpacked struct { C byte Y int16 Z int16 Q int32 } type Packed struct { B [9]byte } func main() { var u Unpacked var p Packed var buf = bytes.NewBuffer(make([]byte, 0, len(pB))) // Unpacked to Packed u = Unpacked{1, 2, 3, 4} if err := binary.Write(buf, binary.BigEndian, &u); err != nil { fmt.Println(err) } if err := binary.Read(buf, binary.BigEndian, &p); err != nil { fmt.Println(err) } fmt.Println("u", u, "to", "p", p) // Packed to Unpacked p = Packed{[...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9}} if err := binary.Write(buf, binary.BigEndian, &p); err != nil { fmt.Println(err) } if err := binary.Read(buf, binary.BigEndian, &u); err != nil { fmt.Println(err) } fmt.Println("p", p, "to", "u", u) } 

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

您可能想要重新考虑您的体系结构 – 尝试将二进制输入传递到C层并使用现有结构(您不会破坏您不更改的内容)。 我假设结构包装看起来像这样:

 #ifdef WINDOWS #pragma pack(push) #endif #pragma pack(BYTEALIGNMENT) // eg "#pragma pack(1)" or "#pragma pack(8)" //--- Some packed structs #ifdef WINDOWS #pragma pack(pop) #endif #ifdef POSIX #pragma pack() #endif 

所有底层或第三方库正在做的是采取一些void *或const char *并将其类型化为这些。 因此,如果可能,尝试将该数据转发到C层(您可以获取指针)并且根本不公开结构。

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

 type AlignTest struct { c byte _ [3]byte // anonymous padding y int16 z int16 q int32 } 

这有效:

 package main import "unsafe" import "fmt" /* struct test { char c; short i; short j; int k; } __attribute__((packed)); */ import "C" type AlignTest struct { c byte y int16 z int16 q int32 } func main() { vr := new(AlignTest) v := new(C.struct_test) fmt.Println(unsafe.Sizeof(*vr), "\n") fmt.Println(unsafe.Sizeof(*v), "\n") } 

输出:

 12 9