Rust 中的结构填充规则

Struct padding rules in Rust

最近在学习Type LayoutRust时,看到Rust中的struct支持#[repr(C)]指令,所以想看看默认(Rust)表示的区别和类 C 的表示。代码来了:

use type_layout::TypeLayout;

#[derive(TypeLayout)]
struct ACG1 {
    time1: u16, // 2
    time2: u16, // 2
    upper: u32, // 4
    lower: u16, // 2
}

#[derive(TypeLayout)]
#[repr(C)]
struct ACG2 {
    time1: u16, // 2
    time2: u16, // 2
    upper: u32, // 4
    lower: u16, // 2
}

fn main() {
    println!("ACG1: {}", ACG1::type_layout());
    println!("ACG2: {}", ACG2::type_layout());
}

我得到以下输出:

我理解填充#[repr(C)] 结构的规则和整个结构的大小,但令我困惑的是 Rust 表示结构 ACG1。我找不到关于Rust padding rules的明确文档,我认为padding size也应该包含在结构的整体大小中,但是为什么ACG1的大小只有12个字节?

顺便说一句,这是我用来协助打印结构布局的箱子:type-layout 0.2.0

这个 crate 似乎没有考虑字段重新排序。编译器似乎重新排序了结构,使其首先具有 upper

struct ACG1 {
    upper: u32,
    time1: u16,
    time2: u16,
    lower: u16,
}

有点难看,但是derive macro implementation检查字段声明顺序之间的差异。所以从这个意义上说,在结构的开头和第一个字段 (time1) 之间有 四个字节的“填充”,第三个字段之间有四个字节的“填充”字段 (upper) 和第四字段 (lower).

an issue 指出它不适用于非 #[repr(C)] 结构,因此我不建议为此目的使用此板条箱。

就 Rust 的规则而言,参考资料说 “[默认] 表示不保证数据布局。” 所以理论上,编译器可以做到无论它想要什么,并根据访问模式重新排序字段。但在实践中,我不认为精心设计和按字段大小组织是最小化填充的简单方法。

正如其他人所说,这似乎是板条箱中的问题。 最好问编译器:

cargo clean
cargo rustc -- -Zprint-type-sizes

这会给你:

...
print-type-size type: `ACG1`: 12 bytes, alignment: 4 bytes
print-type-size     field `.upper`: 4 bytes
print-type-size     field `.time1`: 2 bytes
print-type-size     field `.time2`: 2 bytes
print-type-size     field `.lower`: 2 bytes
print-type-size     end padding: 2 bytes
print-type-size type: `ACG2`: 12 bytes, alignment: 4 bytes
print-type-size     field `.time1`: 2 bytes
print-type-size     field `.time2`: 2 bytes
print-type-size     field `.upper`: 4 bytes
print-type-size     field `.lower`: 2 bytes
print-type-size     end padding: 2 bytes