bigywater.tech
Rust · 113

Struct 对齐与 Padding

填充到底是怎么产生的?编译器自己怎么描述它?不对齐的访问有多慢?这篇让 rustc 自己把布局打印出来,逐字段看到偏移与填充,再验证对齐访问的实际表现。

16 字节
repr(C) 的 MixedC(32 字节)里填充占的字节数
32 对 16
repr(C) 与默认布局同样五个字段的大小
panic
debug 构建里直接解引用不对齐指针的结果

大小与对齐

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
      u8             size  1  align  1
      u16            size  2  align  2
      u32            size  4  align  4
      u64            size  8  align  8
      u128           size 16  align 16
      f64            size  8  align  8
      char           size  4  align  4
      bool           size  1  align  1
      usize          size  8  align  8
      &u8            size  8  align  8
      (u8, u32)      size  8  align  4
      [u16; 3]       size  6  align  2
      S1             size  2  align  1
      S2             size  8  align  4
      S3             size 16  align  8
      S4             size  8  align  2

repr(C) 的基础见#[repr(C)] 与内存布局。

编译器打印的布局

实测 · 本机执行输出
  type: `MixedC`: 32 bytes, alignment: 8 bytes
      field `.a`: 1 bytes
      padding: 7 bytes
      field `.b`: 8 bytes, alignment: 8 bytes
      field `.c`: 1 bytes
      padding: 3 bytes
      field `.d`: 4 bytes, alignment: 4 bytes
      field `.e`: 2 bytes
      end padding: 6 bytes
  type: `Mixed`: 16 bytes, alignment: 8 bytes
      field `.b`: 8 bytes
      field `.d`: 4 bytes
      field `.e`: 2 bytes
      field `.a`: 1 bytes
      field `.c`: 1 bytes

-Z print-type-sizes 需要 RUSTC_BOOTSTRAP=1,输出格式随编译器版本变化。

元素间距

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
    size_of::<S>() = 8,元素间距 = 8 和 8
    每个元素地址 % align(4) = 0 0 0
    一个 u8 数组里偏移 0..8 的位置,按 u32 对齐的占 2 个,不对齐的占 6 个

不对齐访问

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
    对齐的 u32 读取(偏移 0):       每次 0.45 ns
    不对齐的 u32 读取(偏移 1):     每次 0.46 ns(read_unaligned,结果不同是因为读的字节不同:106686713290400000 对 106113205749200000)
  编译:成功
  运行(退出码 -6):
    read_unaligned 读偏移 1 的 u32 = 0x5040302
    
    thread 'main' (7305060) panicked at <实验目录>/src/u113e.rs:6:22:
    misaligned pointer dereference: address must be a multiple of 0x4 but is 0x16b41a7e5
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
    thread caused non-unwinding panic. aborting.

耗时为本机 release 微基准;x86 与 aarch64 上不对齐访问的代价不同,只验证了本机。

分步演示

对齐与填充
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / rustc 1.98.1(brew)/ cargo 1.98.1;单个文件用 rustc 直接编译,需要依赖时用 cargo(经代理从 crates.io 下载);计时用 std::time::Instant,数字每次运行会有小幅抖动。print-type-sizes 用 RUSTC_BOOTSTRAP=1
    • 没有验证:x86_64 上不对齐访问的成本、缓存行对齐(false sharing)、填充字节内容的泄漏风险(未初始化)、repr(align) 在 Vec 中的行为、#[repr(simd)]
    京ICP备2026067502号-1京公网安备11010502063487号