Dan*_*aef 5 c variables memory-address
这可能是一个愚蠢的问题,但我对编程很新,所以请耐心等待.
让我们说为了论证我正在谈论用C编码...
我理解(系统相关)一个int占用4个字节,或32位内存.
但是,这里有两件事让我感到困惑.这段内存有一个与之关联的特定内存地址(也就是说也是32位),如果将这个int存储在一个变量中,那么它也有一个与之关联的名称.
例如int myInt = 5;
我的问题是 - 在位级表示的内存地址和变量名称的方式和位置是什么?在编译代码时,编译器是否基本上说:"好的myInt引用地址0xffffff"并且基本上替换机器代码中的内存地址?即使是这种情况,我仍然对如何表示内存地址本身感到困惑...
我希望我的困惑在哪里清楚!
从理论上讲,答案是“它取决于实现”。每个 C 编译器都会决定采用的最佳方法——只要它表现出正确的行为,如何实现这一点并不重要。
实际上,您可能不会在编译的程序中看到对变量名称的引用。这是因为处理器不需要知道或关心您为执行程序而分配的变量名称。它的运行级别要低得多:它只需要了解要执行哪些指令以及按什么顺序执行。因此,包含这些信息是一种多余的浪费,只会增加程序的大小。
共有三种基本情况,我将在下面列举。我还将描述典型编译器可能会执行的行为,但请记住,它是依赖于实现的,并且一般来说,只要编译器表现出正确的标准行为,就允许编译器执行它们想做的任何操作。
对于局部变量,作为编译过程的一部分,编译器将每个变量名称(例如“int foo;”)替换为对该变量分配的适当内存的引用(“内存地址0x482c”)。对该值的赋值或引用通常可以仅引用适当的地址。
对于非局部变量,编译器会执行额外的解析来确定如何发现,但通常仍然不直接存储变量或函数的名称。
对于根本不是变量的事物(结构体、方法等),编译器根据其做出的决策和已设置的参数执行不同的解析步骤和优化。但在这里,它也不存储变量或函数的名称;而是存储变量或函数的名称。它只是用适当的参考文献替换它。
在某些情况下,在编译器的输出中包含变量名称很有用,例如在调试时。在这些情况下,将创建调试符号表。这是一种将地址映射到对人类有意义的名称的方法,这样当出现崩溃时,您可以看到“Stacktrace:function foo() ...”而不是“Stacktrace:内存地址 0x4572 ...”。
在具有元编程功能的语言中,例如 C#、Ruby 或 Java,名称通常会成为与对象一起存储的元数据的一部分,而不仅仅是用内存地址的查找来替换每个引用。当您想要执行某些在运行时在 C 中几乎不可能实现的巧妙技巧时,该元数据会派上用场,例如询问“此集合中的哪些对象有一个名为 的字段foo?”。
编译代码时,编译器是否基本上会说:“Ok myInt 引用地址 0xffffff”并实质上替换为机器代码中的内存地址?
如果myInt位于堆栈上,则保留距堆栈指针的偏移量。编译器myInt在编译该函数时会记住它的存在。
如果myInt具有全局或文件范围,则它将一直保留到myInt链接器可以决定绝对位置为止。
我仍然对内存地址本身的表示方式感到困惑......
内存中的字节按升序编号。因此,绝对地址或堆栈偏移量int在位级别上看起来都像 an 。