色色色,千古一过,君子失徳小人常乐,大丈夫也难把美人关过。

1. 什么是对齐?

对齐指的是我们在安排某个对象的内存的时候不会随便挑一个 byte 作为开始位置。一般来说对象自己的大小或者是这个对象内部的成员的大小会决定这个对象的对齐属性。
比如一个 int 类型的对象的内存开始地址一定是被 4 整除的,一个 longlong 类型的对象的内存开始地址一定是被 8 整除的;

2. 为什么要对齐?

对齐是为了让现代的体系结构更好的去存储和访问这个对象。比如说这个对象如果是 8bytes,结果跨越了两个 8bytes 块,那么它就不能通过一次 ld 指令(RISCV下)直接读进来了,非常可惜,只能用两个指令。而读取是一件非常关键的事,我们总是希望这样的 memory instructions 尽可能的少。

3. 如何对齐?

这个非常简单,不过多介绍,只需要一些 padding 即可。我们举个例子:

  1. char m1;
  2. double m2;
  3. // 可能总共占用 8 + 8 = 16 bytes
  4. // 也可能总共占用 1 + 8 = 9 bytes
  5. // 这个取决于 m1 被分配到的位置
  6. double m1;
  7. char m2;
  8. // 总共占用 8 + 1 = 9 bytes

4. 结构体的对齐

结构体的对齐稍微复杂一点。首先它内部需要对齐,规则和上面是一模一样的。同时它自己也需要对齐。自己对齐的原因我认为有这样两个:

  1. 我们有时候可能需要把结构体整个都读进来,这样的话对齐会节省指令。
  2. 其实就算结构体不对齐,也可以安排一下让它内部的成员变量都是对齐的,但是这样计算结构体内相对地址变得更加复杂。比如操作系统里用汇编直接去操作结构体内的成员,如果它是内部重新调整的话这样的汇编就写不了了。
  3. 不对齐的话,一个结构体数组中相邻的两个对象的大小可能是不一样大的,不是很合理。