Rust 中的 align_of 和 size_of

int 的 align_of

align_of 是根据读取变量的效率进行计算:

memory  0 1 2 3   4 5 6 7   8 9 10 11
int       good
              baaaaaaad

int 类型占 32bit, 即 4 个字节, 假设 CPU 从 0 位置开始读取, 一次读取 4 个字节正好满足, 所以 int 放在 0123 的位置比放在 3456 的位置更有利于被 CPU 读取. 简而言之, 原始类型的 align_of 就是其 size_of,

下面是 Rust 中原始类型的对齐和大小, 由于 64 位系统的数据总线宽度是 64bit, 导致 i128 和 u128 的对齐和大小不一致.

bool     align: 1,       size: 1
char     align: 4,       size: 4
f32      align: 4,       size: 4
f64      align: 8,       size: 8
i128     align: 8,       size: 16
i16      align: 2,       size: 2
i32      align: 4,       size: 4
i64      align: 8,       size: 8
i8       align: 1,       size: 1
isize    align: 8,       size: 8
u128     align: 8,       size: 16
u16      align: 2,       size: 2
u32      align: 4,       size: 4
u64      align: 8,       size: 8
u8       align: 1,       size: 1
usize    align: 8,       size: 8

结构体的 align_of

一个结构 P, 有三个成员, 如下所示: (假设结构体中成员的声明顺序和在内存中的顺序保持一致)

// in src/main.rs
fn main() {
    use std::mem;

    #[repr(C)]  // 保证成员在内存中的顺序和声明的顺序保持一致 (否则可能被编译器优化)
    struct P {
        i: i32, // size_of = 4
        s: i8,  // size_of = 1
        l: i64, // size_of = 64
    }

    println!("P align: {}", mem::align_of::<P>());
    println!("P size:  {}", mem::size_of::<P>());
}

上面的代码输出:

P align: 8
P size:  16

输出结果显示 P 的 align 和 size 是不一样的, 为什么会这样呢? 看下 P 在内存中的表示:

read        |---    1st  ---|   |---     2nd       ---|
memory      0 1 2 3   4 5 6 7   8 9 10 11   12 13 14 15
P           i------   s         l----------------------         

P 的 align_of 的计算过程:

  • i: 如果一次读取完毕, 需读取 4 个字节, 所以对齐到 4 可以很方便的读取 i.
  • s: 如果一次读取完毕, 需读取 1 个字节, 所以对齐到 1 就可以, 但 i 需要对齐到 4, 所以对齐仍为 4.
  • l: 如果一次读取完毕, 需读取 8 个字节, 所以对齐到 8 可以很方便的读取 l. 于是 P 的对齐就是 8.

P 的 align_of = max({size_of(f)|f∈P}) = max(1, 4, 8) = 8

P 的 size_of 的计算过程:

P 的 align_of = 8, 意味着读取 P 的时候, 每次读取 8 个字节.

  • 第一次读取 8 个字节, 其中包含了 i:i32 和 s:i8
  • 第二次读取 8 个字节, 包含了 l:i64

P 的 size_of = 对齐 * 读取次数 = 8 + 8 = 16

P 变化了

如果在上面的基础上, 增加一个 u8 类型的成员 s2:

fn main() {
    use std::mem;

    #[repr(C)]
    struct P {
        i: i32,
        s: i8,
        s2: i8,
        l: i64,
    }

    println!("P align: {}", mem::align_of::<P>());
    println!("P size:  {}", mem::size_of::<P>());
}

上面的代码输出:

P align: 8
P size:  16

根据结果显示, 虽然增加了一个成员 s2, 但 P 的大小没有变, 仍然是 16, 为什么会这样? 看下 P 在内存中的结构:

read        |---    1st  ---|   |---     2nd       ---|
memory      0 1 2 3   4 5 6 7   8 9 10 11   12 13 14 15
P           i------   s s2      l----------------------         

根据 P 的内存结构计算如下:

align_of = max({sizeof(f)|f∈P}) = max(4, 1, 1, 8) = 8

size_of = 对齐 * 读取次数 = 8 * 2 = 16

原来是这样啊, 无论是否有 s2 这个成员, 5 6 7 这三个字节都被一次性读取了.

P 又变化了

在上面的例子的基础上, 如果把 s2 换个位置, 放在最后:

fn main() {
    use std::mem;

    #[repr(C)]
    struct P {
        i: i32,
        s: i8,
        l: i64,
        s2: i8,
    }

    println!("P align: {}", mem::align_of::<P>());
    println!("P size:  {}", mem::size_of::<P>());
}

上面代码输出:

P align: 8
P size:  24

成员没有增删, 只是移动了位置, 但 P 的大小发生了变化, 怎么回事? 看下内存结构:

read      |---    1st  ---|   |---     2nd       ---|  |---      3rd       ---|        
memory    0 1 2 3   4 5 6 7   8 9 10 11   12 13 14 15  16 17 18 19  20 21 22 23
P         i------   s         l----------------------  s2

align_of = max({sizeof(f)|f∈P}) = max(4, 1, 8, 1) = 8

size_of = 对齐 * 读取次数 = 8 * 3 = 24

s2 虽然只占 1 个字节, 但由于 align = 8, 所以第三次一次性读取了 8 个字节.

练习题

fn main() {
    use std::mem;

    #[repr(C)]
    struct P {
        i: i32,
        s: i8,
        s2: i8,
        s3: i8,
        s4: i8,
        s5: i8,
        l: i64,
    }

    println!("P align: {}", mem::align_of::<P>());
    println!("P size:  {}", mem::size_of::<P>());
}

画一下 P 内存结构, 并计算 P 的大小.

read        |---    1st    ---|     |---     2nd       ---|  |---      3rd       ---|   
memory      0 1 2 3   4 5  6  7     8 9 10 11   12 13 14 15  16 17 18 19  20 21 22 23
P           i------   s s2 s3 s4    s5                       l-----------------------

align_of = max({sizeof(f)|f∈P}) = max(4, 1, 1, 1, 1, 1, 8) = 8

size_of = 对齐 * 读取次数 = 8 * 3 = 24

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值