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
最近在学习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