内存对齐
零 前言
自定义类型也就是:结构体,联合和枚举。这部分的基础知识在前面的文章中我们也详细的讲过。点击阅读
我们这一节主要来讲一相关的些比较重要的知识。
一 结构体
1. 内存对齐
Ⅰ)引入
struct S1 |
上面是一个结构体,也是我们自定义的一种类型。我们知道,任何类型都有大小,那么结构体 S1 的大小是多少?
是结构体各成员变量大小的和吗?如果是的话,那结构体 S1 的大小就是 6
那我们设计一个程序验证一下:
int main(void) { |
输出是:12,这个 12 是怎么得来的呢?
想要知道这个问题答案,那我们就要了解一下 内存对齐。
Ⅱ)为什么要内存对齐?
内存对齐关系到 CPU 读取数据的效率 和 一些其他原因。我们这里不做展开,有兴趣可以自己查一下。
Ⅲ)规则
第一个成员在与结构体变量偏移量为0的地址处。
其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
VS中默认的值为8
结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
四)练习
判断下面结构体的大小:
VS 默认的对齐数是 8,32 位机器
1
struct S1 |
解析:1(char)
(+ 3
(int 应该对齐到 4 的整数倍上,也就是 4,所以应该给 1 加上 3 凑成 4)) + 4(int)
+ 1(char)
(+ 3
最后整个结构体大小为最大对齐数(也就是 4)的整数倍处,所以结构体的大小不是 9 而是 12 )(最大对齐数是最大成员的对齐数,这个是前面算过的(成员大小和默认对齐数取小))
答案:12
2
struct S2 |
第一个例题已经详细的分析了判断结构体大小的步骤,下面不再赘述。
1 (char)
+ 1 (char)
(+2
) + 4 (int)
答案:8
3
struct S3 |
8 (double)
+ 1 (char)
(+3
) + 4 (int)
答案:16
4
struct S3 |
例 3 中,我们已经知道了 S3 的大小是 16
1 (char)
(+ 7
(结构体大小是 16 和 编译器默认对齐数 8 取较小值,所以结构体要对齐的整数倍是 8)) + 16 (S3)
+ 8 (double)
答案:32
不确定你可以自己在你的编译器上敲一下,看看运行结构,前提是编译器的默认对齐数是 8 ,如果不是,结果可能会不一样,那么编译器的默认对齐数可以修改吗?
2. 修改默认对齐数
只需要加上一条指令即可:
如果你想取消设置的默认对齐数,还原为默认:
二 位段
1.了解位段
位段的声明和结构是类似的,有两个不同:
- 位段的成员必须是 int、unsigned int 或signed int 。
- 位段的成员名后边有一个冒号和一个数字。
struct S |
存储方式:
- 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型
- 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
- 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段
位段的应用:
可以自行了解IP数据报格式。