我无法理解调用& *指针
时会发生什么int j=8;
int* p = &j;
当我在编译器中打印时,我得到以下内容
j = 8 , &j = 00EBFEAC p = 00EBFEAC , *p = 8 , &p = 00EBFEA0
&*p= 00EBFEAC
cout << &*p gives &*p = 00EBFEAC which is p itself
&安培;和*具有相同的运算符优先级。我认为&amp; * p将转换为&(*p)--> &(8)
并且预期编译器错误。
编译器如何推断出这个结果?
答案 0 :(得分:4)
你绊倒了一些有趣的东西:严格说来的变量,不是值,但是指的是值。 8
是整数值。在int i=8
之后,i
指的是整数值。不同之处在于它可以引用不同的值。
为了获得该值,必须取消引用i
,即必须获得i
代表的存储位置中存储的值。只要请求变量引用的类型的值,就会在C中隐式执行此解除引用:i=8; printf("%d", i)
产生与printf("%d", 8)
相同的输出。这很有趣,因为变量本质上是地址的别名,而数字文字是立即值的别名。在C中,这些非常不同的东西在句法上被相同地对待。变量可以代表表达式中的文字,并将自动解除引用。生成的机器代码非常清楚。考虑下面的两个功能。两者都有相同的返回类型,int。但是f
在return语句中有一个变量,必须取消引用它才能返回它的值(在这种情况下,它会在寄存器中返回):
int i = 1;
int g(){ return 1; } // literal
int f(){ return i; } // variable
如果我们忽略了内务代码,那么每个函数都会转换成一个sigle机器指令。相应的汇编程序(来自icc)用于g
:
movl $1, %eax #5.17
这非常明星:将1放入寄存器eax。
相比之下,f
转换为
movl i(%rip), %eax #4.17
这将值放在寄存器中的寄存器rip加偏移量i中。令人耳目一新的是,变量名称只是编译器的地址(偏移)别名。
现在必须进行必要的解除引用。为了返回1而编写return *i
并且仅为返回引用的函数或指针编写return i
更合乎逻辑。
在你的例子中,在某种程度上确实是不合逻辑的
int j=8;
int* p = &j;
printf("%d\n", *p);
打印8(即p实际上被解除引用两次);但是&(*p)
产生p指向的对象的地址(这是p中存储的地址值),并且不被解释为&(8)
。原因是在地址运算符的上下文中,变量(或者,在这种情况下,通过解除引用p获得的L值)不隐式地取消引用它在其他上下文中的方式。
当尝试创建逻辑正交语言 - Algol68 - 时,int i=8
确实声明了8的别名。为了声明变量,长形式将是 {{1} } 强> ref
。因此,我们称之为指针或引用的类型为int m = loc int := 3
,因为实际上需要两个解引用才能获得整数值。
答案 1 :(得分:2)
j是一个值为8的int,存储在地址00EBFEAC的内存中。
&amp; j给出变量j(00EBFEAC)的存储器地址。
int * p =&amp; j在这里定义一个变量p,它定义为int *类型,即内存中可以找到int的地址的值。你指定它&amp; j,即int的地址 - &gt;这是有道理的。
* p为您提供与p中存储的地址相关联的值。 存储在p中的地址指向一个int,所以* p给出了该int的值,即8。
&安培; p是变量p本身存储的地址
&amp; * p为您提供存储在p中的内存地址的值的地址,这确实是p。 &amp;(* p) - &gt; &amp;(j) - &gt; 00EBFEAC
答案 2 :(得分:1)
考虑fulfill
本身(甚至是&j
)。根据您的逻辑,我不应该&(j)
评估为8并导致j
吗?取消引用指针或评估变量会产生左值,这是一个可以分配给或取地址的值。
&#34;左值&#34;中的 L 指的是分配&#34;左侧的左侧,例如&8
或j = 10
。还有一些左值,例如*p = 12
或j + 10
,显然无法分配。
这只是一个基本的解释。 In C++ there's a lot more to it,具有各种类别的值(但该线程可能太高级,无法满足您当前的需求)。