C Alignment
花了一点时间⌚️,学习了一下 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。
以上。