C/C++中取地址符&的语义

来源:互联网 发布:淘宝酒仙网有假酒吗 编辑:程序博客网 时间:2024/05/23 01:58

在C语言中,&符号大家一定很熟悉吧。

它除了可以作为按位运算“与”之外还有更常用的功能——取变量地址。

我们首先看下面一个简单的例子:

 

  1. #include <stdio.h>
  2. int main(void)
  3. {
  4.     int a = 0;
  5.     int *p = &a;
  6.     printf("The value is: %d/n", *p);
  7.     return 0;
  8. }

上面代码中,指针p指向变量a的地址。在C/C++中,每个变量都有其相应的地址,通过在变量标识符前加&符号即可获得变量的地址

那么我们这么写可以吗?int *p = &0x01000;

这显然不行。因为对于一个数值常量,它是没有地址的。而变量之所以有地址就是因为要有一个存储单元对变量进行标识(当然,变量也可以直接映射到某个寄存器)。

我们再看下面的代码:

 

  1. #include "stdio.h"
  2. int main(void
  3.     int a = 0; // &a = 0x0012ff60 
  4.     int *p = &*(int*)0x0012ff60; 
  5.     printf("The value is: %d/n", *p); 
  6.     return 0; 
  7. }

 上面代码又是怎么回事呢?

先前已经调查过变量a的地址——0x0012ff60,那么这里的指针p实际上也是指向变量a的地址。

首先,将0x0012ff60作为int*,这时它与&a是等价的。

然后*(int*)0x0012ff60表示取变量a的内容。

最后,&*(int*)0x0012ff60表示再脱去*(int*)0x0012ff60的解引用,相当于又变为(int*)&a。

因此,这里的&与第一个例子中的&是不同的语义。这里的&不是取地址,因为一个*(int*)0x0012ff60不是变量,它是没有地址的。每一个变量标识符在编译期间,编译器会为它们创建一个符号表,其中存放着变量标识符相应的各种属性,如类型、地址标识等。地址标识在连接后即可确定逻辑地址值。简而言之,&作为取地址操作,当且仅当&后面跟着的是变量或函数标识符。所以这里的&表示脱去解引用

由此我们可以得出:&作为取地址操作时,其行为结果是在编译时就被确定的;而*,解引用操作(或取内容)操作,其行为结果只能在运行时才可被确定

 

再看下面的例子,加深印象:

 

  1. #include "stdio.h"
  2. int main(void)
  3. {
  4.     int a = 0;
  5.     int *p = &*&*&a;
  6.     printf("The value is: %d/n", *p);
  7.     return 0;
  8. }

不过,&符号不象解引用*能用多次,它只能放在变量标识符或一次解引用前。下面举一个例子

int main(void){    int a = 100;    int *p = &a;    int **pp = &p;    int **qq = &*&*pp;    // OK    int **rr = *&*&pp;    // OK    int **ss = &&**pp;    // ERROR}

由于经过一次&来脱去解引用之后,当前表达式就不为左值。而&必须放在一个左值前,因为只有左值才能确保引用是有效的,呵呵。


在C++中,&还可以表示引用,这个就不多说了。

  1. #include "iostream"
  2. using namespace std;
  3. int main(void)
  4. {
  5.     int a = 0;
  6.     int &r = a;
  7.     cout << "The value is: " << r << endl;
  8.     return 0;
  9. }


 

原创粉丝点击