0. 先看一道题目
struct A
{
int a;
short b;
int c;
char d;
};
小伙伴一看,肯定心想这不是so easy吗,sizeof(A),我们肯定是认为4+2+4+1=11,所以sizeof(A)=11!
哈哈,那么答案是不是这样呢?我们来分析一波!
1. 结构体中的内存对齐[vs2019环境下]
结构体在内存中存储时,并不是按照上面我们所想的那样,一个一个存放进去的!那么它具体时怎么样的呢?我们来分4个步骤来分析!
1.1 第一步
第一个成员在与结构体变量偏移量为0的地址处。
1.2 第二步
从第二个成员开始,要对齐到某个【对齐数】的整数倍的偏移处。
对齐数:结构体成员自身大小和默认对齐数中的较小值
紧接着第三个成员
最后一个成员
1.3 第三步
结构体的总大小必须是最大对齐数的整数倍!(每个结构体成员都有一个对齐数,其中最大的对齐数就是最大对齐数)
从图中可以看出结构体此时总大小为13,此时并不是最大对齐数4的整数倍,所以应该扩展到16,所以最终sizeof(A)为16!
1.4 第四步【如果存在嵌套结构体的情况下】
如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
先分析B的大小
在分析A的大小
2. 为什么要存在内存对齐呢?
2.1 平台原因
不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2.2 性能原因
数据结构(尤其是栈)应该尽可能地在自然边界上对齐。
原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;
而对齐的内存访问仅需要一次访问。
那在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到:
让占用空间小的成员尽量集中在一起!
例如:
struct S2
{
char c1;
char c2;
int i;
};
3.修改默认对齐数
我们可以通过 pragma pack() 来修改默认对齐数
#include <stdio.h>
#pragma pack(8)//设置默认对齐数为8
struct S1
{
char c1;
int i;
char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
结构在对齐方式不合适的时候,我么可以自己更改默认对齐数。
4. 结束语
看到这里,小伙伴应该明白了为什么一开始的结果和你想的不一样了把!