取消引用如何工作C ++ [英] How does dereference work C++

查看:57
本文介绍了取消引用如何工作C ++的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很难理解调用& * pointer

时会发生什么

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

&和*具有相同的运算符优先级.我认为& * p会转换为&(*p)--> &(8)和预期的编译器错误.

编译器如何得出这个结果?

解决方案

您正在绊倒一些有趣的东西:严格来说,变量不是值,但是指价值观. 8 是一个整数值.在int i=8之后,i 指代一个整数值.区别在于它可以引用不同的值.

为了获得该值,必须取消引用i,即,必须获取存储在i所代表的存储位置中的值.每当请求变量引用的类型的值:i=8; printf("%d", i)产生与printf("%d", 8)相同的输出时,该取消引用就在C中隐式执行.这很有趣,因为变量本质上是地址的别名,而数字文字是立即数的别名.在C语言中,这些非常不同的事物在语法上是相同的.变量可以代表表达式中的文字,并且将自动取消引用.由此产生的机器代码使这一点非常清楚.考虑下面的两个功能.两者都具有相同的返回类型int.但是f在return语句中有一个变量,必须对其进行取消引用,以便可以返回其值(在这种情况下,它在寄存器中返回):

int i = 1;
int g(){ return 1; }  // literal
int f(){ return i; }  // variable

如果我们忽略管家代码,则每个函数都会转换为一个单机指令.相应的汇编器(来自icc)用于g:

    movl      $1, %eax                                      #5.17

这很简单:将1放入寄存器eax.

通过对比,f转换为

    movl      i(%rip), %eax                                 #4.17

这会将值放入寄存器rip中的地址加上寄存器eax中的偏移i.令人耳目一新的是,变量名如何只是编译器的地址(偏移)别名.

必要的解除引用现在应该很明显.编写return *i以便返回1,并且仅对返回引用—的函数编写return i会更合乎逻辑.或指针.

在您的示例中,在一定程度上确实是不合逻辑的

int j=8;
int* p = &j;
printf("%d\n", *p);

打印8(即p实际上被取消引用两次);但是&(*p)会产生p指向的对象的地址(这是存储在p中的地址值),并且不会被解释为&(8).原因是在地址运算符的上下文中,变量(或在这种情况下,通过解引用p获得的L值)不会像在其他上下文中那样隐式地解引用. >

尝试创建逻辑正交语言时-mdash; Algol68—,int i=8确实声明了8的别名.为了声明变量,长格式应为 ref int m = loc int := 3.因此,我们所谓的指针或引用将具有类型ref ref int,因为实际上需要两次取消引用才能获得整数值.

I have trouble understanding what happens when calling &*pointer

int j=8;
int* p = &j;

When I print in my compiler I get the following

j = 8 , &j =  00EBFEAC  p = 00EBFEAC , *p = 8 , &p =  00EBFEA0 
&*p= 00EBFEAC

cout << &*p gives  &*p = 00EBFEAC which is p itself

& and * have same operator precedence.I thought &*p would translate to &(*p)--> &(8) and expected compiler error.

How does compiler deduce this result?

解决方案

You are stumbling over something interesting: Variables, strictly spoken, are not values, but refer to values. 8 is an integer value. After int i=8, i refers to an integer value. The difference is that it could refer to a different value.

In order to obtain the value, i must be dereferenced, i.e. the value stored in the memory location which i stands for must be obtained. This dereferencing is performed implicitly in C whenever a value of the type which the variable references is requested: i=8; printf("%d", i) results in the same output as printf("%d", 8). That is funny because variables are essentially aliases for addresses, while numeric literals are aliases for immediate values. In C these very different things are syntactically treated identically. A variable can stand in for a literal in an expression and will be automatically dereferenced. The resulting machine code makes that very clear. Consider the two functions below. Both have the same return type, int. But f has a variable in the return statement which must be dereferenced so that its value can be returned (in this case, it is returned in a register):

int i = 1;
int g(){ return 1; }  // literal
int f(){ return i; }  // variable

If we ignore the housekeeping code, the functions each translate into a sigle machine instruction. The corresponding assembler (from icc) is for g:

    movl      $1, %eax                                      #5.17

That's pretty starightforward: Put 1 in the register eax.

By contrast, f translates to

    movl      i(%rip), %eax                                 #4.17

This puts the value at the address in register rip plus offset i in the register eax. It's refreshing to see how a variable name is just an address (offset) alias to the compiler.

The necessary dereferencing should now be obvious. It would be more logical to write return *i in order to return 1, and write return i only for functions which return references — or pointers.

In your example it is indeed illogical to a degree that

int j=8;
int* p = &j;
printf("%d\n", *p);

prints 8 (i.e, p is actually dereferenced twice); but that &(*p) yields the address of the object pointed to by p (which is the address value stored in p), and is not interpreted as &(8). The reason is that in the context of the address operator a variable (or, in this case, the L-value obtained by dereferencing p) is not implicitly dereferenced the way it is in other contexts.

When the attempt was made to create a logical, orthogonal language — Algol68 —, int i=8 indeed declared an alias for 8. In order to declare a variable the long form would have been refint m = loc int := 3. Consequently what we call a pointer or reference would have had the type ref ref int because actually two dereferences are needed to obtain an integer value.

这篇关于取消引用如何工作C ++的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆