目录
一、结构体的对齐规则:
1.
第一个成员在与结构体变量偏移量为
0
的地址处。
2.
其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数
=
编译器默认的一个对齐数 与 该成员大小的
较小值
。
VS
中默认的值为
8
Linux
中是没有默认对对齐数的
3.
结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4.
如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
注意:可以使用offesrof - 宏
来计算结构体成员相对于起始位置的偏移量
#include<stddef.h>
printf("%u\n", offsetof(struct S1, c1));
二、为什么存在内存对齐
1. 平台原因(移植原因):
不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2. 性能原因:
数据结构
(
尤其是栈
)
应该尽可能地在自然边界上对齐。 原因在于,为了访问未对齐的内存,处理器
需要作两次内存访问;而对齐的内存访问仅需要一次访问。
总体来说:
结构体的内存对齐是拿空间来换取时间的做法。
那在设计结构体的时候,我们既要满足对齐,又要节省空间,
让占用空间小的成员尽量集中在一起。
例如:
struct S1
{
char c1; // 1 内存位置0
int i; // 4 内存位置4
char c2; // 1 内存位置8
};
struct S2
{
char c1;
char c2;
int i;
};
S1的内存图示:
0 | c1 |
1 | 空 |
2 | 空 |
3 | 空 |
4 | i |
5 | i |
6 | i |
7 | i |
8 | c2 |
9 | 空 |
10 | 空 |
11 | 空 |
S2的内存图示
0 | c1 |
1 | c2 |
2 | 空 |
3 | 空 |
4 | i |
5 | i |
6 | i |
7 | i |
结构体s1的内存因为内存对齐的原因,大小为12。结构体s2内存大小为8.
S1
和
S2
类型的成员一模一样,但是
S1
和
S2
所占空间的大小有了一些区别。
三、结构体的嵌套问题
如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
struct S3
{
double d;
char c1;
int i;
};
struct S4
{
char c1;
struct S3 s3;
double d;
};
int main()
{
struct S3 s;
printf("%d\n", sizeof(s));
printf("%d\n", sizeof(struct S4));
return 0;
}
嵌套的结构体对齐到自己的最大对齐数的整数倍处,S3中最大为8,所有均已8对齐
结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍,也是8
s4的内存图示:
0 | c1 | 8 | s3 | 16 | s3 | 24 | d |
1 | 空 | 9 | s3 | 17 | s3 | 25 | d |
2 | 空 | 10 | s3 | 18 | s3 | 26 | d |
3 | 空 | 11 | s3 | 19 | s3 | 27 | d |
4 | 空 | 12 | s3 | 20 | s3 | 28 | d |
5 | 空 | 13 | s3 | 21 | s3 | 29 | d |
6 | 空 | 14 | s3 | 22 | s3 | 30 | d |
7 | 空 | 15 | s3 | 23 | s3 | 31 | d |
四、修改默认对齐数
正常情况下下面结构体内存为16
struct S
{
char c1;
double d;
};
用 #pragma 这个预处理指令,可以改变我们的默认对齐数
#pragma pack(4) 设置默认对齐数为4
struct S
{
char c1;
double d;
};
#pragma pack() 取消设置的默认对齐数,还原为默认
上的结构体s 的内存占用为12
0 | c1 |
1 | 空 |
2 | 空 |
3 | 空 |
4 | d |
5 | d |
6 | d |
7 | d |
8 | d |
9 | d |
10 | d |
11 | d |
例:
#pragma pack(2)
struct S2
{
char c1;
int i;
char c2;
};
#pragma pack()
int main()
{
printf("%d\n", sizeof(struct S2));
return 0;
}
S2结构体内存大小为8