fix error(struct.md): struct memory layout size.

This commit is contained in:
matrix
2022-03-25 12:08:47 +08:00
parent b7bf0be59d
commit ab8fedb1e3

View File

@@ -147,14 +147,53 @@ numbers[0].denominator = 7;
上面示例声明了一个有1000个成员的数组`numbers`,每个成员都是自定义类型`fraction`的实例。
struct 结构占用的存储空间,不是各个属性存储空间的总和。因为为了计算效率C 语言的内存占用空间一般来说,都必须是`int`类型存储空间的倍数。如果`int`类型的存储是4字节那么 struct 类型的存储空间就总是4的倍数
struct 结构占用的存储空间,不是各个属性存储空间的总和而是最大内存占用元素的倍数占位不足的元素会进行对齐填充。比如以64位机器为例
```c
struct { char a; int b; } s;
printf("%d\n", sizeof(s)); // 8
// 占24个字节sizeof(struct foo) = 24;
struct foo {
int a;
char *b;
char c;
};
```
在64位机器中`int a`占4个字节指针`char *b`类型占8个字节`char c`占1个字节实际有效存储空间13字节。但编译器会进行内存对齐填充即向占用内存空间最大的指针`char *b`对齐,具体做法是空位填充。
```c
struct foo {
int a; // 4
char pad1[4]; // 填充4字节
char *b; // 8
char c; // 1
char pad2[7]; // 填充7字节
};
```
为什么浪费这么多内存空间进行内存对齐这是为了减少CPU的访存次数毕竟比起高速运转的CPU和寄存器访存是最耗时间的操作。一般情况让变量的存储地址是它占用字节的倍数例如让`long`型变量的地址是8的倍数(例如: 0x0008)`int`型变量的地址是4的倍数`short`型是2的倍数`char`占一个字节,但一般都会在`char`型变量后进行空字节填充即使不是在结构体中。这样处理后CPU就可以按照字或者半字寻址一次访存就定位到变量的起始地址。
上面示例中,如果按照属性占据的空间相加,变量`s`的存储空间应该是5个字节。但是struct 结构的存储空间是`int`类型的倍数所以最后的结果是占据8个字节`a`属性与`b`属性之间有3个字节的“空洞”
由于结构体的这一特性,一般在定义结构体的时候,采用内存占用递减进行元素排序,这样可以比较有效的优化内存占用,原因如下
```c
// 占24个字节sizeof(struct foo) = 24;
struct foo {
int a;
char *b;
char c;
};
// 内存占用递减排序元素占16个字节sizeof(struct foo) = 16;
struct foo {
char *b;
int a;
char c;
};
```
上边代码,改变了结构体中`char *b``int a`的顺序内存占用就从24字节下降到16字节因为此时编译器只需要进行尾填充即可。
```c
// 占16个字节sizeof(struct foo) = 24;
struct foo {
char *b; // 8
int a; // 4
char c; // 1
char pad[3]; // 填充3字节
};
```
## struct 的复制