如何用 #[repr(u8)] 控制枚举大小?
解读
国内面试官问“如何用 #[repr(u8)] 控制枚举大小”时,真正想考察的是你对 Rust 内存布局、ABI 可控性以及 FFI/嵌入式场景下“字节级对齐”的理解深度。
他们并不满足于“加属性就能变小”这种表面答案,而是希望听到:
- 默认 discriminant 类型如何决定枚举大小;
- 为什么 u8 能把 64 位机器上的 tag 从 8 字节压到 1 字节;
- 什么时候会触发编译器拒绝;
- 与 C 交互时如何防止“布局踩踏”;
- 在高性能场景里如何利用 repr(u8) 做“零成本状态机”。
一句话:面试官要的是“能把内存省到字节、还能讲出风险”的候选人。
知识点
- 默认布局:Rust 枚举默认使用 isize 作为 discriminant,对齐到机器字长,64 位下 tag 占 8 字节,导致空枚举也占 8 字节。
- #[repr(Int)] 族:显式指定 discriminant 的整型,Int ∈ {u8, u16, u32, u64, i8…},同时保持 Rust 的“tagged union”语义不变。
- 大小计算规则:
size = max(variant_payload) 的对齐后大小 + discriminant 大小,再整体对齐到 max(align(max_payload), align(discriminant))。
因此把 discriminant 从 8 字节压到 1 字节,可直接省 7 字节,且整体对齐可能从 8 降到 1。 - 安全性边界:
- 当变体带数据时,repr(u8) 不会做任何位级压缩,不会引入未定义行为;
- 若手动给 discriminant 赋值超出 u8 范围(>255),编译器 直接报错,而非静默截断;
- 与 C 交互时,必须保证 C 端结构体也用 uint8_t 作为 tag,否则 ABI 不一致。
- 零成本状态机:在嵌入式或网络协议解析中,用 repr(u8) 枚举做阶段标记,既保证单字节存储,又能用 match 获得分支预测友好的跳转表。
- 与 repr(C) 区别:repr(C) 只保证 C 兼容的 布局顺序,不压缩 tag;repr(u8) 既压缩 tag 又保留 Rust 语义,两者可叠加:#[repr(C, u8)],此时布局与 C 的 tagged union 完全一致,方便裸指针转换。
答案
#[repr(u8)] // 强制 discriminant 为 u8
enum State {
Init = 0,
Running = 1,
Done = 2,
}
fn main() {
use std::mem;
println!("size = {}", mem::size_of::<State>()); // 输出 1
}
步骤拆解:
- 在 enum 前加
#[repr(u8)],编译器把 tag 类型从默认 isize 改为 u8; - 由于三个变体都不带数据,payload 大小为 0,最终大小等于 1 字节;
- 若变体带数据,例如
Running(u32),则大小为 4(payload)+ 1(tag)再对齐到 4,共 5 字节,但对齐到 4 后实际占 8 字节; - 如果尝试
#[repr(u8)] enum Foo { X = 256 },编译器 立刻报错:literal out of range for u8; - 与 C 交互时,C 端对应定义
即可安全 transmute。typedef struct { uint8_t tag; union { ... } data; } State;
拓展思考
- 单字节枚举的位级技巧:在嵌入式寄存器映射中,可把 repr(u8) 枚举再包一层
#[repr(transparent)] struct Reg(u8),实现“强类型 + 单字节 MMIO”,既防止误写非法状态,又保证零开销。 - 与 const-generic 结合:做协议解析时,用
#[repr(u8)] enum Phase<const N: u8>,编译期即可算出最大合法 discriminant,避免手工维护魔数。 - 风险案例:某国产数据库曾把
#[repr(u8)]枚举通过 FFI 传给 C++,但 C++ 端 tag 声明为enum class : uint32_t,导致高位 3 字节未初始化,在 ARM 大端机器上触发 UB。修复方案是 Rust 端改用 #[repr(C, u32)],保持两边宽度一致。 - 面试加分话术:
“除了省内存,repr(u8) 还能让状态机数组直接映射到 flash 段,做到常量表与代码段同址,减少一次 load 指令;在 48 MHz 的 Cortex-M0 上,我实测把协议解析延迟从 2.1 µs 降到 1.3 µs。”
这类量化数据是国内面试官最愿意听到的“工程落地感”。