我们在计算结构体大小的时候,会按照我们认为的逻辑去计算,实际是不对的,这涉及到了结构体的内存对齐的相关知识,下面我来用我的理解介绍一下结构体的内存对齐
我先说一下内存对齐的几个要点:
1.结构体的第一个成员,对齐到结构体在内存中存放位置的0偏移处
2.从第二个成员开始,每个成员都要对齐到(一个对齐数)的整数倍处
3.对齐数:结构体自身成员大小和默认对齐数的较小值
4.VS默认对齐数:8
Linux gcc:没有默认对齐数,对齐数就是结构体成员的自身大小
5.结构体的总大小,必须是所有成员的对齐数中最大对齐数的整数倍
6.如果结构体中嵌套了结构体成员,要将嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处。
7.结构体的总大小必须是最大对齐数的整数倍,这里的最大对齐数是:包含嵌套结构体成员中的对齐数,的所有对齐数中的最大值
到这里我知道你们可能看不懂,下面我用图跟代码结合的方式来展示
//下面这两个结构体,都是两个char,一个int,
//char的大小是1,int是4,所以我们第一眼就会以为这两个结构体的大小都是6,可是不一样,第一个是12,第二个是8
struct S1
{
char c1;
int i;
char c2;
};
struct S1
{
char c1;
char c2;
int i;
};
struct S3
{
double d;
char c;
int i;
};//这个结构体通过上面的方法算出来大小是16
struct S4
{
char c1;
struct S3 s3;
double d;
};//这里主要讲要点6和7
为什么存在内存对齐?
1.平台原因:不是所有的硬件平台都能访问任意地址上的任意数据;某些平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2.性能原因:
数据结构(尤其是栈),应该尽可能地在自然边界上对齐。
原因在于,为了访问未对齐的内存,处理器需要作两次访问;而对齐的内存仅需要一次访问。
总体来说:结构体的内存对齐是拿空间来换取时间的做法。
那么在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到呢?
就是让占用空间小的成员尽量集中在一起。
怎么修改默认对齐数呢?
#include<stdio.h>
#pragma pack(1)//设置默认对齐数为1
struct s1
{
char ci;
char c2;
int i;
};
#pragma pack()//取消程序自己的默认对齐数
结构体在对齐方式不合适的时候,我们要自己更改默认对齐数