结构体内存对齐
结构体内存对齐的原则
- 结构体内第一个变量成员默认处在偏移量为0的地址处
- 其他成员变量要对齐到某个数字(对齐数的)的整数倍的地址处
对齐数 = 编译器默认的一个对齐数与该成员变量大小的较小值( VS中默认的对齐数为8)
VS下, 对齐数 = min(8,sizeof(变量类型)) - 结构体总大小为最大对齐数(结构体内所有变量对齐数的最大值)的整数倍
- 结构体嵌套结构体的情况下,嵌套的结构体对齐到自己最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
暂时不理解没有关系,我们对着下面的例子一一讲解内存对齐的规则。
结构体大小的运算
例1:
struct A
{
char _c1;
char _c2;
int _i;
};
int main ()
{
printf("%d\n", sizeof(struct A)); // 8
system("pause");
}
例2:
struct B
{
char _c1;
int _i;
char _c2;
}
int main ()
{
printf("%d\n", sizeof(struct A)); // 12
system("pause");
}
例3:
struct S3
{
double d;
char c;
int i;
};
int main()
{
printf("%d\n",sizeof(struct S3)); //16
}
例4:
struct S
{
char c1;
struct S3 s3;
double d;
};
int main()
{
printf("%d\n", sizeof(struct S));
}
修改默认对齐数
#pragma pack() 改变我们的默认对齐数
#pragma pack(8) -------- 设置默认对齐数为8
#pragma pack() -------- 取消设置的默认对齐数,还原为默认
#pragma pack(1) -------- 设置默认对齐数为1
我们再来看一下,非VS默认对齐数下的结构体大小
#pragma pack(4)
struct S3
{
double d;
char c;
int i;
};
#pragma pack(4)
struct S
{
char c1;
struct S3 s3;
double d;
};
int main()
{
printf("%d\n", sizeof(struct S));
}
在这里只是将VS默认的对齐数8修改为4。只要按照上面的计算方法按步骤计算,就可以得到答案了。
我在这里简单的说一下,读者们也下去也要勤于思考,熟能生巧。
(): 变量所占的字节数, []补上的空的字节数。
S3 结构体的大小: d(8)c(1)[3]i(4) 所以 sizeof(S3) = 8 + 1 + 3 + 4 = 16;
S结构体的大小: c1(1)[3]s3(16)d(8) 所以 sizeof(S) = 1 + 3 + 16 + 8 = 28;
为什么要内存对齐?
我们再来看一个结构体
struct A
{
char _ch;
int _i;
}
对齐的话,如果cpu访问变量_i只用读取一次内存(读取一次内存肯定是4的倍数)
不对齐的话,如果cpu要想访问变量_i就有可能读取两次内存,在进行拼接,才能访问到_i.
为什么内存对齐,总结来说:
- 平台原因: 不是所有的硬件平台都能访问任意地址上的任意数据。某些硬件平台只能在某些地址处取某些特定类型的数据。
- 性能原因: cpu访问的次数会影响cpu处理数据的性能。