C语言 CPU 和内存通信



我是程序员初学者,但我想更深入地理解这些东西。我做了一些研究,阅读了很多文字,但我仍然没有理解一些东西。

当编写一个基本的东西(用 C 语言(时:

int myNumber;
myNumber = 3;
printf("Here's my number: %d", myNumber);

我发现(主要在 32 位 CPU 上(整数代替了 32 位 = 4 个字节。因此,在我的代码的第一行,CPU进入内存。内存是字节可寻址的,因此 CPU 为我的变量选择 4 个连续字节,并将地址存储到第一个(或最后一个(字节。

在我的代码的第二行,CPU 使用他存储的 MyNumber 变量地址,转到内存中的该地址并找到 32 位保留空间。他现在的任务是在那里存储数字"3",所以他用序列00000000-00000000-00000000-00000000-00000011填充这四个字节。在第三行,它执行相同的操作 - CPU 转到内存中的该地址并加载存储在该地址中的数字。

(第一个问题 - 我理解正确吗?

我不明白的是:
该地址(指向该变量的指针(的大小在 32 位 CPU 中为 4 字节。(这就是为什么 32 位 CPU 最多可以使用 4GB 内存 - 因为只有 2^32 个二进制长度为 32 的不同地址(
现在,CPU 将这些地址存储在哪里?他是否有某种自己的内存或缓存来存储它?为什么它将 32 位长的地址存储为 32 位长的整数?当大小相同时,简单地将实际数字存储在其缓存中比指向该数字的指针更好吗?

最后一个 - 如果它存储在自己的缓存中的某个地方,所有这些整数的地址和长度都相同(4 字节(,它将需要与实际变量完全相同的空间来存储地址。但是变量最多可以占用 4GB 的空间,因此 CPU 必须有 4GB 自己的空间来存储这些变量的地址。这听起来很奇怪。

谢谢你的帮助!
我试图理解这一点,但这太难了。:-[

(第一个问题 - 我理解正确吗?

首先要认识到的是,该值可能根本不存储在主内存中。 编译器可能会决定将其存储在寄存器中,因为这更理想。1

内存是字节可寻址的,因此 CPU 为我的变量选择 4 个连续字节,并将地址存储到第一个(或最后一个(字节。

假设编译器确实决定将其存储在主内存中,那么是的,在 32 位计算机上,int通常为 4 个字节,因此将分配 4 个字节用于存储。

地址(指向该变量的指针(的大小在 32 位 CPU 中为 4 字节。(这就是为什么 32 位 CPU 最多可以使用 4GB 内存 - 因为只有 2^32 个二进制长度为 32 的不同地址(

请注意,int的宽度和指针的宽度不必相同,因此不一定与地址空间的大小有联系。

现在,CPU 将这些地址存储在哪里?

对于局部变量,地址被有效地硬编码到可执行文件本身中,通常作为堆栈指针的偏移量。

在动态分配的对象(即被malloc-ed的东西(的情况下,程序员通常维护一个相应的指针变量(否则会有内存泄漏! 该指针也可能是动态分配的(在复杂数据结构的情况下(,但如果你回到足够远的地方,你最终会得到一个局部变量。 在这种情况下,上述规则适用。

但是变量最多可以占用 4GB 的空间,因此 CPU 必须有 4GB 自己的空间来存储这些变量的地址。

如果您的程序由独立malloc数百万个int组成,那么是的,您最终会获得指针所需的同样多的存储空间。 但大多数程序看起来不是这样。 您通常会分配更大的对象(如数组或大结构(。

缓存

存储内容的细节是特定于体系结构的。 在现代 x86 上,CPU 和主内存之间通常有 2 或 3 层缓存。 但是缓存不是可独立寻址的;CPU 无法决定将int存储在缓存中而不是主内存。 相反,缓存实际上是主内存子集的冗余副本。

要考虑的另一件事是,编译器在为对象分配存储时通常会处理虚拟地址。 在现代 x86 上,这些通过专用硬件映射到物理地址(即对应于主内存中的物理存储字节的地址(以及操作系统支持。


1. 或者,编译器可以完全优化它。

在我的代码的第二行,CPU 使用他存储的 MyNumber 变量地址,转到内存中的该地址并找到 32 位保留空间。

几乎正确。内存基本上是非结构化的。CPU 看不到有 32 位"保留空间"。但是 CPU 被指示读取 32 位数据,因此它从指定地址开始读取 32 位数据。然后它只需要希望/假设这 32 位实际上包含一些有意义的东西。

现在,CPU 将这些地址存储在哪里?他是否有某种自己的内存或缓存来存储它?为什么它将 32 位长的地址存储为 32 位长的整数?当大小相同时,简单地将实际数字存储在其缓存中比指向该数字的指针更好吗?

CPU 具有少量寄存器,

可用于存储数据(普通 CPU 有 8、16 或 32 个寄存器,因此它们只能保存您此时此地正在使用的特定变量(。因此,首先回答最后一部分,是的,编译器肯定会(并且可能会(生成代码以仅将int存储到寄存器中,而不是将其存储在内存中,并告诉CPU从指定地址加载它。至于问题的另一部分:最终,程序的每个部分都存储在内存中。其中一部分是指令流,一部分是分散在内存中的数据块。

有一些技巧可以帮助定位CPU所需的数据:程序内存的一部分包含堆栈,该堆栈通常在局部变量在范围内存储它们时。CPU 始终在其寄存器之一中维护指向堆栈顶部的指针,因此只需使用固定偏移量修改堆栈指针即可轻松定位堆栈上的数据。指令可以直接包含这样的偏移量,所以为了读取你的int,编译器可以生成代码,当你输入函数时,将int写入堆栈的顶部,然后当你需要引用该函数时,有代码读取在堆栈指针指向的地址找到的数据, 加上定位变量所需的小偏移量。

还要记住,你的程序看到的地址可能不是(或者很少是(从"内存的开始"或0开始的物理地址。大多数情况下,它们是偏移到一个特定的内存块中,内存管理器知道真实地址和通过base+offest作为真实数据存储的访问。

而且我们确实需要内存,因为缓存是有限的;-(

马里奥

在CPU内部有一个寄存器,其中包含要执行的下一条指令的地址。指令本身将信息保留在变量所在的位置。如果变量被优化,指令可能指向寄存器,但一般来说,指令将具有被访问变量的地址。您的代码在编译并加载到内存中后,已经嵌入了所有内容!我建议研究汇编语言以更好地理解所有这些。祝你好运!

最新更新