2024年10月11日 12:16

This commit is contained in:
许大仙 2024-10-11 04:16:07 +00:00
parent d4a8fbaa11
commit 48a17acf0a
5 changed files with 74 additions and 2 deletions

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 77 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 148 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 148 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 123 KiB

View File

@ -1313,8 +1313,64 @@ int main() {
> [!NOTE]
>
> * ① 对于一个 int 类型的数据而言,其在内存中的长度是 4 个字节。
> * ② 如果其存储时的内存地址的编号是 8 ,非常好办,直接对编号为 8 的内存进行寻址一次就可以了。
> * ③ 但是,如果其存储时的内存地址的编号是 10就比较麻烦CPU 首先需要先对编号为 8 的内存进行寻址,读取 4 个字节,得到该数据的前半部分,然后再对编号为 12 的内存进行寻址,读取 4 个字节,得到该数据的后半部分,再将这两部分数据拼接起来,才能取得数据的值。
>
> ![](./assets/14.svg)
>
> * ② 如果其存储时的内存地址的编号是 4 ,非常好办,直接对编号为 4 的内存进行寻址一次就可以了。
>
> ![](./assets/15.svg)
>
> * ③ 如果其存储时的内存地址的编号是 6就比较麻烦CPU 首先需要先对编号为 4 的内存进行寻址,读取 4 个字节,得到该数据的前半部分,然后再对编号为 8 的内存进行寻址,读取 4 个字节,得到该数据的后半部分,再将这两部分数据拼接起来,才能取得数据的值。
>
> ![](./assets/16.svg)
> [!IMPORTANT]
>
> * ① 将一个数据尽量放到一个步长之内,避免跨步长存储和读取,这称为`内存对齐`。
> * ② 在 `32` 位编译模式下,默认以 `4` 字节对齐。在 `64` 位编译模式下,默认以 `8` 字节对齐。
* 为了满足对齐要求,编译器有时会在数据结构中插入一些“填充”字节,这就会产生一定的内存浪费。例如:假设一个结构体包含一个`char`和一个`int`字段,编译器可能会插入 3 个字节的填充以确保`int`字段对齐到 4 字节的边界。这种填充虽然会浪费少量内存,但可以显著提升数据访问效率,如下所示:
```c
#include <stdio.h>
struct {
int a;
char b;
int c;
} t = {10, 'C', 20};
int main() {
// 禁用 stdout 缓冲区
setbuf(stdout, nullptr);
printf("sizeof(t): %zu\n", sizeof(t)); // sizeof(t): 12
printf("&a: %p\n", &t.a); // &a: 0x559d28db8010
printf("&b: %p\n", &t.b); // &b: 0x559d28db8014
printf("&c: %p\n", &t.c); // &c: 0x559d28db8018
return 0;
}
```
* 其内存结构,如下所示:
![](./assets/17.svg)
> [!CAUTION]
>
> * ① 不管是`结构体变量`,还是`普通变量`都存在内存对齐。
> * ② 内存对齐的规则:只能存放在自己类型整数倍的内存地址上(`内存地址`和`占用字节`是可以整除)。
> * 1 字节的数据,如:`char`类型,通常可以存放在任何地址。
> * 2 字节的数据,如:`short`类型,通常存放在偶数地址。
> * 4 字节的数据,如:`int`类型,通常存放在能被 4 整除的地址。
> * 8 字节的数据,如:`double`类型,通常存放在能被 8 整除的地址。
> * ③ `结构体变量`的内存对齐:`结构体变量`的内存对齐除了遵循上述的内存规则之外,还会插入“填充”字节。`结构体变量`的总大小是最大类型的整数倍。
> * ④ 内存对齐的时候可能会出现“填充”字节但是并不会改变原来数据的大小char 类型的数据即使“填充”字节之后,本身还是 1 个字节。
> * ⑤ `心得`:我们会将小的数据类型,写在最上面;大的数据类型,写在最下面(节省内存空间)。