What is actually going on in C when a non-pointer value is stored?
重要信息:这试图一次询问太多的事情,并且具有误导性,因为我在关于如何使用指针的错误假设下编写了它,并且最终看起来像一个重复项。请改为查看:变量如何与C中的值绑定?
让我们考虑在地址0001处有一个值4,然后将地址0001分配给变量num。我们可以将其可视化为两个表:
1 2
| VARIABLE|ADDRESS ADDRESS|VALUE
num |0001 0001 |4 |
据我了解,这将是以下代码的最终产品:
1 2
| int temp = 4;
int * num = &temp; |
但是,第一行int temp = 4;是怎么回事?第一行会产生这样的结果吗?
1 2
| VARIABLE|ADDRESS ADDRESS|VALUE
| temp |4 |
指针如何工作?代码是否会:
1 2 3
| int temp = 4;
int * num = &temp;
int ** pnum = # |
产生这个?
1 2 3
| VARIABLE|ADDRESS ADDRESS|VALUE
num |0001 0001 |4
pnum |0002 0002 |0001 |
对此有什么正确的想法?实际情况到底是怎么回事?另外,当存储结构而不是数字时,这会如何变化?
我了解上述示例可能完全不正确;他们只是将我的问题具体化。
-
原始值存储在堆栈上,因此,相对于封装值声明的函数,您提到的第一行将值4存储在堆栈上(有关堆栈内存使用的更多信息,请参见:stackoverflow.com/questions/79923/)
-
"思考这个问题的正确方法是什么?"对我来说,我发现这很不错:temp的地址在" int street"上,门牌号为" 123"。 temp的值为4。num的地址位于" int * street"上,门牌号为" 456"。 num的值为" int street:123"。" int street"和" int * street"可能是指相同的"街道",也可能不是。不确定这种抽象是否适合学习者。实际发生的情况取决于编译器和处理器-没有人回答-太宽泛了。
-
还有一个表(在编译时)说,名称temp表示地址0001
-
123421重复的先前问题如何?它们与您的问题有何关系?
-
无论如何,您的表在概念上都是错误的。指针具有地址和值。分配给指针的值是一个地址,但不是指针本身的地址。
-
链接重复项的答案基本上给出了与该问题所述完全相同的方案,并显示了变量如何最终存储在内存中。
-
@AnttiHaapala我找不到任何具体询问内存中实际发生的问题,最简单的是寻求概念性理解。您链接到的问题不会询问内存中实际发生了什么;它只是在寻找概念上的理解。即使您可以链接一个与我的匹配的问题,也不需要您的粗鲁评论。
-
@Lundin即使这样,对像我这样的问题进行搜索查询的人也不会轻易找到答案,尤其是因为1)人们将浏览问题标题,以及2)即使他们选择查看该问题及其答案也是如此。答案,他们不太可能找到该特定答案,因为它是很长答案页面上的第五个答案。
-
@Lundin Yep,确实可以正确回答我的问题。在这里要做的适当的事情是用答案的链接"回答我自己的问题"吗?该问题仅要求获得概念上的理解,但实际上,该答案是我的问题的答案,该问题要求了解实际机制。您是否仍然认为我的问题重复了?
-
@NetherGranite如果重复项中有答案可以回答这个问题,那通常就足够了。这个问题在某种程度上已经被问过很多次了,人们通常不会费心去寻找完美的骗子。查找重复项的问题是SO系统的已知缺陷,并且在meta.stackoverflow上进行了无休止的辩论。
-
@Lundin等待,我刚刚意识到答案实际上并没有回答我最初的问题,即当非指针值分配给变量时会发生什么。即使这样做,将某物标记为重复项的标准也是否是"现有问题的完全重复项",而我的不是。
-
@NetherGranite所有变量都有一个地址,无论是否用指针指向它们。如果您愿意,我可以重新打开问题,但是我怀疑您会得到更好的答案。
-
@Lundin实际上,我相信我已经看不到我最初的要求。我将尝试提出一个新问题,并试图更好地阐明我到底在寻找什么。抱歉,添麻烦了。
并非所有变量都需要在内存系统中有一个地址,有些变量寿命很短,因此可以在寄存器中保留整个寿命。在这种情况下,它们会由编译器分配(重命名)为eax,ebx或r1,r2之类的东西。寄存器是CPU中可以容纳变量内容的插槽。
由于许多架构的寄存器数量有限(x86-64中有8个虚拟(对机器语言可见)寄存器,IA64中有256个寄存器...),其余变量将分配(编译)到内??存中的地址,这将总是在堆栈上。堆栈(由esp寄存器(一个特殊的寄存器跟踪))是一个后进先出的分配器,具有操作系统的支持(随着内存页面的增长,内存页面会不断增长),因此编译器只需采用当前的堆栈指针并对其进行递增由要分配的变量的大小决定,这就是变量的地址。
就像您在第一种情况中所展示的那样,值的分配是通过发出带有硬编码值的mov汇编命令来完成的,因此常量存在于程序的存储空间中。这意味着该值来自指令本身。 (L1:inst缓存->提取程序-> CPU管道-> mov-> STORE管道-> L1:数据缓存)
其余的工作就像您感觉到的那样。
-
您在x64中忘记了r8-r15。
-
确实是@liliscent。 让我们将此链接作为x64寄存器的参考en.wikibooks.org/wiki/X86_Assembly/