内存对齐规则
- 对齐系数(也叫对齐模数):gcc中默认
#pragma pack(4)
,可以通过预编译命令 #pragma pack(n),n = 1,2,4,8,16 来改变这一系数 - 有效对齐值:是给定值 #pragma pack(n) 和结构体中 最长数据类型长度中较小的那个。有效对齐值也叫 对齐单位
-
规则一:结构体第一个成员的偏移量 offset 为 0,以后每个成员相对于结构体首地址的 offset 都是该成员大小与有效对齐值中较小那个的整数倍,如有需要编译器会在成员之间加上填充字节
-
规则二:结构体的总大小为 有效对齐值 的整数倍,如有需要编译器会在最末一个成员之后加上填充字节
注意:上面两条规则都需要得到满足
注意:成员变量首地址偏移和对齐都是与【有效对齐值】进行比较,而有效对齐值是对齐系数与结构体中最长数据类型中的较小者
// 64 位程序
struct
{
int i;
char c1;
char c2;
}x1;
struct{
char c1;
int i;
char c2;
}x2;
struct{
char c1;
char c2;
int i;
}x3;
struct
{
short i;
char c1;
char c2;
}y1;
struct{
char c1;
short i;
char c2;
}y2;
struct{
char c1;
char c2;
short i;
}y3;
int main()
{
printf("%ld\n",sizeof(x1)); // 输出8
printf("%ld\n",sizeof(x2)); // 输出12
printf("%ld\n",sizeof(x3)); // 输出8
cout << "----------------" << endl;
printf("%ld\n",sizeof(y1)); // 输出4
printf("%ld\n",sizeof(y2)); // 输出6
printf("%ld\n",sizeof(y3)); // 输出4
return 0;
}
既要考虑首地址偏移,又要是有效对齐值(对齐单位)的整数倍
y1 y2 y3结构体:
以上测试都是在 Linux 环境下进行的,linux 下默认 #pragma pack(4),且结构体中最长的数据类型为 2 个字节,所以有效对齐单位为 2 字节,下面根据上面所说的规则以 y2 来分析其内存布局:
首先使用规则 1,对成员变量进行对齐:
sizeof(c1) = 1 <= 2 (有效对齐位),按照 1 字节对齐,占用第 0 单元;
sizeof(i) = 2 <= 2 (有效对齐位),相对于结构体首地址的偏移要为 2 的倍数,占用第 2,3 单元;
sizeof(c2) = 1 <= 2 (有效对齐位),相对于结构体首地址的偏移要为 1 的倍数,占用第 4 单元;
然后使用规则 2,对结构体整体进行对齐:
y2 中变量 i 占用内存最大占 2 字节,而有对齐系数为 4 字节,两者较小值就是 2 字节。因此整体也是按照 2 字节对齐。由规则 1 得到 y2 占 5 个字节,此处再按照规则 2 进行整体的 2 字节对齐,所以整个结构体占用 6 个字节。