花了一点时间⌚️,学习了一下 C 语言中对齐的知识,在这里做个总结。

对齐(Alignment)是为了提高计算机处理器和内存系统之间的交互效率而出现的 一种概念。它要求每种数据类型的地址都应是其 K 值的整数倍。对于 Intel x86-64 架构中,类型和其对应的 K 值对应关系如下:

类型 K 值
char 1
short 2
int 4
long 8
float 4
double 8
char * 8

这样做的好处就是可以避免处理器从内存系统中取数据时,一个类型横跨两个内存块的情况。 对于结构体类型,我们要求其中的所有成员都应该按照各自的 K 值进行对齐。如果某一成员 的地址不是其 K 值的整数倍,那么应该在其前面 append 一些字节使得地址是其 K 值的整数 倍。因为我们还有可能定义结构体数组,所以我们也要保证数组中的每个结构体成员中的元素 按照其 K 值对齐,而且还要保证每个结构体成员的大小必须一致。这样我们就可以得出一个结论: 结构体的 K 值等于其成员 K 值的最大值。对于有嵌套结构体的情况,我们应该把嵌套的 结构体展开,再去找其中成员 K 值的最大值

下面我们举个例子来说明一下:

struct {
    char *a;
    short b;
    double c;
    char d;
    float e;
    char f;
    long g;
    int h;
} rec;

这个结构体每个成员的 offset 和实际大小如下表所求:

成员 K 值 offset 实际大小
char *a 8 0 8
short b 2 8 8 (2 + 6)
double c 8 16 (8 + 2 + 6) 8
char d 1 24 (16 + 8) 4 (1 + 3)
float e 4 28 (24 + 1 + 3) 4
char f 1 32 8 (1 + 7)
long g 8 40 (32 + 1 + 7) 8
int h 4 48 (40 + 8) 8 (4 + 4)

上表中的 offset 是指将结构体的开始地址设为 0,然后每个成员相对于起始地址的偏移量;最后一列 实际大小 指的是为了满足对齐规则每个成员所占用的实际存储空间。这里要提一点,上表中最后一行 ,int 类型的变量 h 的实际大小为 8,这是因为考虑到结构体数组的情况,下一个结构体的起始地址必须 满足 char *a 的对齐要求,所以要给 h 添加 4 字节的存储空间。

此外,我们还可以从上表中看出,整个结构体的大小就是最后一列的所有数字相加,为 56 byte。整个结构 体的对齐 K 值为其中成员的 K 值的最大值,这里是 8。

以上。