C中的结构体&共用体内存对齐
1.为何存在内存对齐
大致的说法如下:
a.为了方便移植,某些平台只能在特定地址处区某些特定类型的数据
b.为了提高效率,对于访问未对齐的内存,处理器需要做两次访问,而对齐的内存访问仅需要一次。
以32位机器来说,当一个字符型的数据与一个整型数据依次存储,char a int b
考虑到系统的数据线宽度为32,当访问a时因为a仅占一个字节,当不存在内存对齐时CPU必然会访问到b的某个位置,于是当我们接着访问b时处理器就需要做2次访问。
根本上来说,结构体的内存对齐就是拿空间换取时间。
2.结构体的内存对齐规则
1.第一个成员在与结构体变量偏移量为0的地址处,也就是说结构体的起始地址与其第一个成员的地址是等价的。
2.其他成员变量要对齐到其对齐数的整数倍地址处,
对齐数 = min{编译器默认对齐数,该成员占用字节数};
以VS,VSCODE为例,编译器默认对齐数为8;
3.结构体的总大小为最大对齐数的整数倍
4.如果存在嵌套结构体,该内部嵌套的结构体对齐到自己的成员的整数倍,外部结构体即所有的最大对齐数的整数倍(包括嵌套结构体)
举例
a.`struct u1`
`{`
`char q;`//对齐数为1,//q本来占一个字节,但是
`int data;`//对齐数为4,因此其对齐位置要到4的倍数,这里是4,故q也要占用四个字节,浪费了三个字节
`char w;`//与q同理
`};`
最终占用4*3=12个字节。
`b.struct u2 { char c1; char c2; int i; }; //因为i的对齐数为4,所以c1占用一个字节,c2占用三个字节,i占用4个字节,故占用八个字节`
`c.struct u3 { double d; char c; int i; };//double的对齐数为8,因此整个结构体的字节数必须为8的倍数,c占四个字节,i占四个字节,共16个字节`
`d.struct u4 { char c1; struct u3 u; double d; };//首先u的最大对齐数在前面已经求得为8,d也是8,所以必须为8的倍数,而u本身占用16字节,故最终共占用32字节。``
3.共用体的内存对齐规则
我们知道,共用体的成员共用一块内存空间,其大小至少是最大成员的大小。当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。
举例
union w
{
char c[5];//对齐数为1,至少占用5字节
int i;``//对齐数为4,
};//综上,空间大小至少大于5,但同时要是最大对齐数4的倍数,故占用8字节空间
union Un2
{
short c[7];//对齐数为2,至少占用2*7=14字节`
int i;//对齐数为4`
};综上占用16字节
4.启示
在编写程序时,为节省空间,可适当将占用内存小的集中在一起,如选择
struct S2 { char c1; char c2; int i; };而非struct S1 { char c1; int i; char c2; };
还可以修改默认对齐数,如
#pragma pack(8)//设置默认对齐数为8`
struct S1 { char c1; int i; char c2; };`
#pragma pack()//取消设置的默认对齐数,还原为默认`
部分参考:https://www.bilibili.com/video/BV1TT4y1F7Z9?p=184

2051

被折叠的 条评论
为什么被折叠?



