底层必备c知识之结构体

在上篇文章简单的介绍了结构体的知识 c/c++结构体复习
这篇学习下内存对齐的知识

先说点不知道对不对的历史~~~

我们现在的计算机还是冯诺依曼机,遵循分诺依曼思想,核心的五大控件+程序存储思想, 程序是静态的保存在磁盘上, 要想运行这个程序, 要把程序指令读到内存中,CPU去内存中读取指令执行;
在CPU中, 不是按字节去读取数据, 是根据一个字(word)去读取数据, 16位一个字是2个字节, 32位一个字是4个字节, 64位一个字是8个字节;

为什么要做内存对齐

根据一个字(word)去读取数据,提高性能,减少CPU读取次数,典型的以空间换时间的场景。


结构体

struct num {
  int a;
  int b;
  int c;
} num_1;

你以为的结构体占用空间的大小就是内部成员占用的总大小吗?
sizeof(num_1.a)+sizeof(num_1.b)+sizeof(num_1.c)
上面这个示例的结构大小为 sizeof(num_1) 为12个

占用内存大小

但实际操作却不是 4+4+4 = 12的道理

接着下面这个示例

struct num {
  char a;
  int b;
  double c;
} num_1;
WX20201015-150015.png

16是这个结构体在内存中分配的大小, 13是结构体成员加起来的大小, 但是结果却不一样,这就涉及到了结构体在内存中是如何对齐的?
我们发现16大于13,这是为什么?
并且16是double类型的2倍,这又是为什么?


如果把上例改为

struct num {
  char a;
  int b;
} num_1;
内存对齐

发现打印结果不是5, 而是8, 8又是int类型大小的2倍。这又是为什么??
了解了内存对齐原则后, 这些问题自然迎刃而解。

对齐规则总结

  1. 成员对齐
    结构体的成员是一个一个按顺序放进去的, 但并不是紧密排列的, 从offset为0开始,第一个成员放到这个位置, 之后的每个成员所存储的开始位置都是这个成员本身大小的整倍数

当char a 按一字节划分到首地址offset为0的位置,
当int b分配时,按理应分配到1这个位置,但根据成员对齐规则所知, 所存储位置的开始位置必须是自身类型大小的整倍数,所以从位置4开始存储;
成员double c从8开始存储, 所以共用了16个字节来存储结构体;


A-分配图

如果改成这个样

struct num {
  char a;
  double b;
} num_1;

它也会占用16个字节。


B-分配图

double之前空着的内存可以随便增加变量, 内存也不会增加。


C-分配图

  1. 总内存对齐
struct num {
  char a;
  int b;
  char c;
} num_1;
打印结果

这个结构体的大小却不是 4+4+1 = 9; 打印结果是12
这要涉及到另一个对齐规则,在经过对齐原则分析后,检查计算出的存储单元是否为所有元素中所占内存最大的元素的长度的整数倍,是,则结束;若不是,则补齐为它的整数倍。
如果4+4+1 = 9不是结构体中最大成员b的整倍数时,要补齐成它的整倍数12.

你可能感兴趣的:(底层必备c知识之结构体)