enums - 为什么使一个枚举变体成为 `f64` 会增加此枚举的大小?

标签 enums rust

我创建了三个几乎相同的枚举:

#[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/

相关文章:

java - 将枚举保存在数据库中的方法

c# - 仅为部分成员指定值的枚举

rust - 为什么声明的泛型类型多于它使用的泛型类型的函数需要类型注释?

rust - 为什么对已删除对象的可变引用仍算作可变引用?

rust - 如何将结构方法中的 &self 与另一个结构进行比较

request - 如何在 Rust 中使用 tokio_proto 和 tokio_service 流式传输消息

c - 映射枚举和字符串

Powershell:我可以将现有枚举用作我自己函数的参数吗?

wpf - 如何使用枚举器控制 XAML 中的角色/权限

generics - 无法在Rust的递归枚举中推断泛型函数的类型