一. 结构体内存的计算方式
先给几个例子
例1:
struct s1
{
char c1;
int i;
char c2;
};
例2:
struct s2
{
int i;
char c1;
char c2;
};
以上两个例子的内存大小是否一样?
我们来运行一下
运行程序之后可以观察到这两个结构体内存大小竟然不一样,那我们应该如何计算结构体内存大小呢?
结构体在计算其大小的时候有一定的对其规则
结构体对齐规则:
1.结构体的第一个成员,对其到结构体在内存中存放位置的0偏移处
2.从第二个成员开始,每个成员都要对齐到一个对齐数的整数倍处
对齐数:结构体自身大小和默认对齐数的较小值
例:VS的默认对齐数为 8,linux,gcc没有对齐数,对齐数就是成员自身大小
3.结构体的总大小,必须是所以成员的对齐数中最大对齐数的整数倍
4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的总大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍
我们自己来算一下例1,例2
在vs环境下:
例1:
struct s1
{
char c1;
int i;
char c2;
};
根据上图可以看到,该结构体浪费了六个字节
例2:
struct s2
{
int i;
char c1;
char c2;
};
一般都使用struct s2这种顺序,因为例2相对例1而言节省了4个字节的空间
我们在计算结构体的大小时会遇到很多情况:
例3:
结构体嵌套该怎么计算?
struct C3
{
double d;
char c;
int i;
};
struct C4
{
char c1;
struct C3 c3;
double d;
};
先算出struct C3的结构体大小
根据结构体对齐规则得出struct C3的大小为:16
然后根据规则4
注:是到31,这里往下多对齐了一个
我们来运行看一下结构体大小是否为32
运行结果:
例4:
结构体中含有数组怎么计算?
struct s2
{
char c1;
int a[5];
char c2;
};
计算时将int a[5]看成5个int a //对齐数为4 ,int a[5]是一个连续的空间
1 + 27 = 28 我们来看看结果对不对呢!
运行结果:
二. 为什么存在结构对齐?
大部分参考资料是这样写的:
1.平台原因(移植原因):
不是所有的硬件平台都能访问任意位置上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常
2.性能原因
数据结构(尤其是栈)应尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要访问2次内存;而对齐的内存访问仅需要一次访问
例:
没对齐之前:访问i的空间需要访问2次
对齐之后:访问i只需要访问一次
三.修改默认对齐数
在设计结构体的时候,我们即要满足对齐,又要节省空间,如何做到:
让占用空间小的成员尽量在一起
vs环境下默认对齐数位:8
使用#pragma pack()可以调节默认对齐数
例:
#pragma pack(1) //修改默认对齐数为1
struct s1
{
char c1;
int i;
char c2;
};
运行程序: