Go结构体大小必须用unsafe.Sizeof验证,字段偏移须用unsafe.Offsetof实测;字段顺序影响padding,如Bad{a bool; b int64}为24字节,Good{b int64; a bool}仅16字节,因对齐规则要求字段起始地址为自身Alignof倍数,末尾还需整体对齐。

Go结构体大小不能靠字段类型大小加总得出,unsafe.Sizeof 才是唯一可信结果;字段顺序不对,padding可能翻倍,16字节变24字节很常见。
怎么算字段起始偏移?用 unsafe.Offsetof,别猜
每个字段的起始地址不是“上一个字段结束位置+1”,而是向上取整到本字段对齐值的倍数。比如 int64 对齐值是 8,前面字段结束在偏移 9,那它就得跳到 16 才能放——中间空出的 6 字节就是 padding。
-
unsafe.Alignof(uint16(0)) == 2表示该类型变量自身地址必须是 2 的倍数,但它在 struct 里具体在哪,取决于前面所有字段的累积大小和对齐规则 - 真正验证字段位置,必须用
unsafe.Offsetof(T{}.field),而不是靠类型大小推算 - 嵌套 struct 的对齐值会继承内部最大对齐值,比如内嵌含
int64的 struct,外层整体对齐值就变成 8
为什么 unsafe.Sizeof 结果比手算大?因为结构体总大小要对齐到最大字段对齐值
结构体末尾会自动补 padding,使总大小成为所有字段中最大 unsafe.Alignof 值的整数倍。比如含 int64(对齐 8),哪怕实际字段只占 13 字节,最终也会补到 16。
- 未优化:
type Bad struct { a bool; b int64; c bool }→unsafe.Sizeof返回 24(a 占 1,补 7 对齐 b;b 占 8;c 占 1,再补 7 满足整体 8 字节对齐) - 优化后:
type Good struct { b int64; a bool; c bool }→ 占 16(b:0,a:8,c:9,末尾补 6 到 16) - 空 struct
struct{}大小为 0,但参与对齐计算:若它前面结束在奇数地址,后面字段仍要按自己对齐值跳转
cgo 场景下对齐不一致会直接 panic,必须显式同步
C 和 Go 默认对齐策略不同,尤其当 C 端用了 #pragma pack(1) 或 __attribute__((packed)),而 Go 端没适配,读写就会越界或静默错位。
立即学习“go语言免费学习笔记(深入)”;
- 不要依赖字段顺序“碰巧一致”——C 头文件改一行,Go 端就可能崩溃
- 验证方法:用
C.sizeof_struct_xxx和unsafe.Sizeof(GoStruct{})对比,不等就一定有问题 - 同步手段包括:在 Go struct 中插入
_ uint32填充、调整字段顺序、或在// #include前加对应 pragma 声明
对齐不是编译器优化选项,是硬件访问约束;字段重排不是风格偏好,是节省内存的硬性操作;最易被忽略的是嵌套 struct 的对齐传染性和 cgo 场景下无提示的静默错位。


















