解引用如何工作C ++

时间:2015-09-23 07:31:38

标签: operator-keyword

我无法理解调用& *指针

时会发生什么
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)并且预期编译器错误。

编译器如何推断出这个结果?

3 个答案:

答案 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;左侧的左侧,例如&8j = 10。还有一些左值,例如*p = 12j + 10,显然无法分配。

这只是一个基本的解释。 In C++ there's a lot more to it,具有各种类别的值(但该线程可能太高级,无法满足您当前的需求)。