通常,其内存中的计算机分配 4 个字节...
整句话完全正确。只是,有不同类型的分配。最简单的一种是计算机在某个时刻拥有一定量的空闲和连续内存。当一个程序启动时,所有(空闲和连续的)内存都被分配给新程序。程序完全有责任管理内存,并且不在该内存区域之外写入。这就是 DOS(实模式)的工作方式——非常简单。程序(好吧,它的运行时)只被告知内存区域的开始和结束地址。它将一些“基”寄存器“映射”到该 ram,例如,地址 0 指的是起始地址,程序可能知道变量 X 所在的位置。更先进的操作系统超越,例如,使用阻止程序尝试在其允许的 ram 之外读取或写入的机制。甚至超越,更复杂的操作系统最初可以为程序提供一些内存,然后在程序要求时提供更多内存。
现在,我的疑问是 x 如何指代内存位置。参考存储在哪里以及如何存储?
通常,引用根本不存储在(编译的)程序中。你(程序员)称之为“X”的东西,因为程序只是变成了一个地址。第一个变量地址 0,第二个变量地址 4,以此类推。调试符号,当不被剥离时,跟踪赋予地址的“高级”名称;但它们被调试器使用,并且在技术上不是“程序”的一部分。
当我们使用 x 时,它如何知道引用该内存位置。
让我们编写一个简单的 C 程序:
int x = 15;
int y = 20;
int s;
s = x+y;
编译器看到“int x”并将地址0分配给x。然后看到“int y”并将其分配地址4。然后将地址8分配给“s”。当然,这些地址在整个编译过程中都会被记住。同时它看到那些“x=15”和“y=20”,因此输出这些指令:
"store an integer of 4 bytes, value 15, at address 0"
"store an integer ..., 20, at address 4"
最后它看到“s=x+y”并输出:
"take in the left hand the int (4 bytes) value at address 0"
"take in the right hand the int value at address 4"
"poor the left hand in the right hand"
"poor the right hand in 4 bytes at address 8"
如您所见,不再有 xy 或 s,只有地址(这是一个非常简化的解释)。
这对于 java 和 python 等不同的语言有什么不同吗?
是的,但不要太多。变量的名称总是指地址。纯解释型语言必须记着名字,因为编译和执行之间没有分离,而像java这样的中间语言(我说中间是因为java既是编译器又是解释器)可以做更复杂的事情。
这对于不同的数据类型有什么不同吗?
对于简单类型,没有。在 C 语言中,如果我们不考虑指针和堆,所有变量都被同等对待,只是它们的长度发生了变化。一个 int 可以是 4 个字节长,一个 char 可能是一个字节,一个数组的长度由程序员指定,但变量总是指向包含该值的缓冲区的第一个位置。编译器为每个变量保留它的地址、类型、长度,因此当它遇到源中的变量名称时,它可以知道要做什么(要编译什么指令)。
编辑“你能告诉我编译过程中计算机中的“x 变为 0”部分是如何发生的吗?
它的概念非常简单。编译器读取源代码的文本。每次遇到变量声明时,它都会为其分配第一个空闲地址,然后将其增加变量的大小。开始时,该地址为 0。编译器读取“int x;”后,x 的地址变为 0,“当前”地址递增(对于 int,可能为 4 或 8)。变量名称、它们的类型和它们的地址被保留,并形成一个查找表. 该表用于检查您是否没有两次声明标识符,并用于在源引用已声明的变量时知道在哪里读取和写入。如果源引用了未声明的变量,编译器会报错,因为它在查找表中找不到该变量。请注意:您发布了一个视频链接,该视频讨论了指针;指针也是变量,但它们引入了其他概念。我所说的地址也适用于指针,因为它们只是变量,但它们的值的使用方式不同——我不明白你为什么坚持使用它们。