例如,在我们定义变量之后:
int a=2;
之后我们可以使用“a”作为2 在我第一次学习c / c ++的时候,我认为它是理所当然的 但在我学会了“指针”的概念和变量的地址之后,我很困惑。
如果int* p=&i;
,其中“i”是int。我知道p具有i的地址,所以我们可以使用* p来获取i的值。但如果我们走得更远,“p”如何被访问?看来p必须用名字引用,对吗?
到现在为止,通过地址访问变量对我来说更自然,更容易理解
但现在,当使用最简单的方法访问变量时,我对这种机制感到困惑
与int a=2;
的情况一样,存储名称“a”在哪里?
为什么我们使用“a”,它相当于访问存储“a”或“2”的内存的行为?
答案 0 :(得分:9)
此处a
只是一个符号名称。如果它是局部变量,则不会存储在任何地方。编译器只是在编译阶段使用它,引用实际值(可以在堆栈或寄存器中),然后丢弃。
如果查看编译器生成的程序集,您会注意到a
没有出现(或者可能在注释中)。编译器将适合您的变量,之后只需使用该位置(如x86上的eax
寄存器)。
如果您查看了一个LLVM程序集(非常有趣),您会注意到编译器只将您的变量视为@1
,@2
,@3
... < / p>
另一方面,如果a
是一个全局变量(和一个非static
),则该名称实际上将在符号表中用于引用该变量。但它反过来了 - 变量将被放置在没有名称的地方,符号表会将该名称映射到该位置,以便其他程序可以找到它。
作为旁注:如果程序是使用调试数据编译的,那么名称a
将存储在那里,以便调试器可以显示它以帮助您了解正在发生的事情。
答案 1 :(得分:3)
这称为抽象。故意未指定存储a
的方式和位置。编译器会为您处理它。
实际上,如果a
是函数内部的局部变量,它将在调用时存储在该函数的堆栈帧中。堆栈帧的布局在编译时确定,并且在此之后不会改变。实际上,编译器将生成a
的相对地址(相对于堆栈帧的开始),在实际执行该函数时将转换为绝对地址,并且起始地址堆栈框架已知。
答案 2 :(得分:2)
在编译和链接过程之后,所有符号如“a”和“p”都将转换为地址。符号仅用于按名称使用它们的函数。它就像是内存地址的标记。即使“p”保存地址“a”,编译器也会将指针“p”更改为地址。