我创建了三个几乎相同的枚举:
#[derive(Clone, Debug)]
pub enum Smoller {
Int(u8),
Four([u8; 4]),
Eight([u8; 8]),
Twelve([u8; 12]),
Sixteen([u8; 16]),
}
#[derive(Clone, Debug)]
pub enum Smol {
Float(f32),
Four([u8; 4]),
Eight([u8; 8]),
Twelve([u8; 12]),
Sixteen([u8; 16]),
}
#[derive(Clone, Debug)]
pub enum Big {
Float(f64),
Four([u8; 4]),
Eight([u8; 8]),
Twelve([u8; 12]),
Sixteen([u8; 16]),
}
pub fn main() {
println!("Smoller: {}", std::mem::size_of::<Smoller>()); // => Smoller: 17
println!("Smol: {}", std::mem::size_of::<Smol>()); // => Smol: 20
println!("Big: {}", std::mem::size_of::<Big>()); // => Big: 24
}
根据我对计算机和内存的理解,我期望它们的大小应该相同。最大的变体是 [u8; 16]
大小为 16。因此,虽然这些枚举确实具有不同大小的第一个变体,但它们具有相同的最大变体大小和相同数量的变体总数。
我知道 Rust 可以做一些优化来确认某些类型何时存在间隙(例如,指针可能会崩溃,因为我们知道它们将无效且为 0),但这实际上恰恰相反。我想如果我手动构造这个枚举,我可以将它放入 17 个字节(区分只需要一个字节),所以 20 个字节和 24 个字节都让我感到困惑。
我怀疑这可能与对齐有关,但我不知道为什么,也不知道为什么有必要这样做。
谁能解释一下?
谢谢!
最佳答案
大小必须至少为 17 字节,因为它的最大变体有 16 字节大,并且它需要一个额外的字节用于判别式(编译器在某些情况下可以很聪明,将判别式放在变体的未使用位中,但它不能在这里执行此操作)。
此外,Big
的大小必须是 align 的 8 字节的倍数f64
正确。 8 大于 17 的较小倍数是 24。
同样,Smol
不能只有 17 个字节,因为它的大小必须是 4 个字节的倍数(f32
的大小)。 Smoller
仅包含 u8
,因此它可以对齐到 1 个字节。
关于enums - 为什么使一个枚举变体成为 `f64` 会增加此枚举的大小?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57250993/