struct s
{
char a;
int b;
int c;
}
printf("%d",sizeof(s));
大家首先看看这个结构体的大小。
有些同学们可能 会说,char占一个字节大小,int占4个字节,这不就是9个字节吗。
我们来看看运行结果
出现这个结果的原因是因为结构体存在着内存对齐。
我们来看看内存对齐的出现的原因:
平台原因(移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的;某些平台只能在某些地址处取得某些特定类型的数据,否则抛出硬件异常。
比如,当一个平台要取一个整型数据时只能在地址为4的倍数的位置取得,那么这时就需要内存对齐,否则无法访问到该整型数据。
性能原因: 数据结构(尤其是栈)应该尽可能的在自然边界上对齐。原因在于,为了访问未对齐内存,处理器需要作两次内存访问;而对齐的内存访问仅需一次。
在画图时可能有博友会想,内存这么重要,在进行内存对齐的时候怎么还有内存被白白浪费掉呢?
现在看来,其实结构体的内存对齐是拿空间来换取时间的做法。
举个例子
这个结构体,当要读取i数据时,当没有内存对齐时,可能要出现两次读取
但当内存对齐之后,一次读取就够了
所以结构体的大小该如何计算呢?
1.给地址进行标号,第一个成员的起始地址为0。
2.其余成员所在的地址必须是对齐数的整数倍。
对齐数=编译器默认的一个对齐数和成员大小的较小值。
vs中默认是8.
成员大小 vs对齐数 对齐数
char: 1 8 1
int 4 8 4
所以当int对齐的时候
需要对齐在4的整数倍上
3.结构体的总体大小是最大对齐数的整数倍。
结构体总大小刚好是最大对齐数的整数倍。
注意:大多数情况下,成员变量已经占用的总字节个数并不一定正好为其成员变量中的最大对齐数的整数倍,这时我们需要将其扩大为最大对齐数的整数倍。
4.如果嵌套了结构体,结构体对齐到最大对齐数的整数倍。
结构体成员变量的顺序不同,可能会造成内存不必要的损失。将占用空间小的成员尽量集中在一起,可以有效地避免内存不必要的浪费。
修改默认对齐数
我们也可以修改默认的对齐数
#pragma pack()
如果在该预处理命令的括号内填上数字,那么默认对齐数将会被改为对应数字;如果只使用该预处理命令,不在括号内填写数字,那么会恢复为编译器默认的对齐数。