從彙編角度看引用

一,彙編分析引用:

引用類型到底是什麼?它和指針有什麼關係?它本身佔用內存空間嗎? 帶着這些疑問,我們來進行分析。 先看代碼:

#include <stdio.h>
#include <iostream>
 
using namespace std;
 
void main()
{
   int x = 1;
   int &b = x;
 } 
  通過彙編查看代碼如下:

9:       int x = 1;
00401048   mov         dword ptr [ebp-4],1
10:      int &b = x;
0040104F   lea         eax,[ebp-4]
00401052   mov         dword ptr [ebp-8],eax
  可以知道x的地址爲ebp-4,b的地址爲ebp-8,因爲棧內的變量內存是從高往低進行分配的。所以b的地址比x的低。
  lea eax,[ebp-4]  這條語句將x的地址ebp-4放入eax寄存器

  mov dword ptr [ebp-8],eax 這條語句將eax的值放入b的地址ebp-8中

  上面兩條彙編的作用即:將x的地址存入變量b中,這不和將某個變量的地址存入指針變量是一樣的嗎?

   所以從彙編層次來看,的確引用是通過指針來實現的。

   下面我們通過程序來驗證,我們知道,在程序一層我們只要直接涉及到引用變量的操作,我們操作的總是被引用變量,即編譯器幫我們做了些手腳,總是在引用前面加上*。所以我們要讀取真正的“引用變量的值”,必須採取一定的策略,好吧,我們就按照變量在棧中分佈的特點來繞過編譯器的這個特點。

#include <stdio.h>
#include <iostream>
 
using namespace std;
 
void main()
{
   int x = 1;
   int y = 2;
   int &b = x;
   printf("&x=%x,&y=%x,&b=%x,b=%x\n",&x,&y,&y-1,*(&y-1));
 } 
  輸出結果爲:&x=12ff7c,&y=12ff78,&b=12ff74,b=12ff7c
  Press any key to continue

void main()
{
   int x = 1;
   int &b = x;
   printf("&x=%x,&b=%x\n",&x,&b);
 } 
 
  輸出結果爲::&x=12ff7c,&b=12ff7c.

  b的地址我們沒法通過&b獲得,因爲編譯器會將&b解釋爲:&(*b) =&x ,所以&b將得到&x。也驗證了對所有的b的操作,和對x的操作等同。

  但是我們可以間接通過&y-1來得到b的地址,從而得到b的值:*(&y-1)  從結果可以知道,b的值即x的地址,從而可以知道,從地層實現來看,引用變量的確存放的是被引用對象的地址,只不過,對於高級程序員來說是透明的,編譯器屏蔽了引用和指針的差別。

  下面是程序的變量在內存棧中的分佈,引用變量一樣也佔用內存空間,而且應該是4個字節的空間。

   雖然從底層來說,引用的實質是指針,但是從高層語言級別來看,我們不能說引用就是指針,他們是兩個完全不同的概念。有人說引用是受限的指針,這種說法我不贊同,因爲從語言級別上,指針和引用沒有關係,引用就是另一個變量的別名。對引用的任何操作等價於對被引用變量的操作。從語言級別上,我們就不要去考慮它的底層實現機制啦,因爲這些對你是透明的。所以在面試的時候,如果面試的人問到這個問題,可以先從語言級別上談談引用,深入的話就從底層的實現機制進行分析。而不能什麼條件沒有就說:引用就是指針,沒有差別,......之類的回答
         

以下內容摘自網上,覺得挺好的,借用過來

  什麼是引用? 

  對象的別名(另一個名稱)。

  引用經常用於“按引用傳遞(pass-by-reference)”:

 void swap(int& i, int& j)
 {
   int tmp = i;
   i = j;
   j = tmp;
 }
 
 int main()
 {
   int x, y;
   // ...
   swap(x,y);
 }
  此處的 i 和 j 分別是main中的 x 和 y。換句話說,i 就是x —— 並非指向 x 的指針,也不是x 的拷貝,而是 x 本身。對 i 的任何改變同樣會影響x,反之亦然。

  OK,這就是作爲一個程序員所認知的引用。現在,給你一個不同的角度,這可能會讓你更糊塗,那就是引用是如何實現的。典型的情況下,對象 x 的引用i 是x 的機器地址。但是,當程序員寫 i++ 時,編譯器產生增加 x 的代碼。更詳細的來說,編譯器用來尋找x 的地址位並沒有被改變。C 程序員將此認爲好像是 C 風格的按指針傳遞,只是句法不同 (1) 將 & 從調用者移到了被調用者處,(2)消除了*s。換句話說,C 程序員會將i 看作爲宏(*p),而 p 就是指向 x 的指針(例如,編譯器自動地將潛在的指針解除引用;i++被改變爲(*p)++;i = 7 被自動地轉變成*p = 7)。
 

二,和指針的區別:

定義: 

1、引用: 

C++是C語言的繼承,它可進行過程化程序設計,又可以進行以抽象數據類型爲特點的基於對象的程序設計,還可以進行以繼承和多態爲特點的面向對象的程序設計。引用就是C++對C語言的重要擴充。引用就是某一變量的一個別名,對引用的操作與對變量直接操作完全一樣。引用的聲明方法:類型標識符 &引用名=目標變量名;引用引入了對象的一個同義詞。定義引用的表示方法與定義指針相似,只是用&代替了*。 

2、指針: 

指針利用地址,它的值直接指向存在電腦存儲器中另一個地方的值。由於通過地址能找到所需的變量單元,可以說,地址指向該變量單元。因此,將地址形象化的稱爲“指針”。意思是通過它能找到以它爲地址的內存單元。 

區別: 

1、指針有自己的一塊空間,而引用只是一個別名; 

2、使用sizeof看一個指針的大小是4,而引用則是被引用對象的大小; 

3、指針可以被初始化爲NULL,而引用必須被初始化且必須是一個已有對象的引用; 

4、作爲參數傳遞時,指針需要被解引用纔可以對對象進行操作,而直接對引用的修改都會改變引用所指向的對象; 

5、可以有const指針,但是沒有const引用; 

6、指針在使用中可以指向其它對象,但是引用只能是一個對象的引用,不能 被改變; 

7、指針可以有多級指針(**p),而引用至於一級; 

8、指針和引用使用++運算符的意義不一樣; 

9、如果返回動態內存分配的對象或者內存,必須使用指針,引用可能引起內存泄露。

三,關於引用不能再更改綁定對象的理解

C++Primer教材上說引用不能再改變綁定搞得對象,也就是引用再第二次賦值。

可是下面的程序能正常運行,不會出錯。這裏怎麼出現了引用賦值語句呢(語句[1])?是不是教材錯了?原因究竟是什麼呢? 

請看如下程序:

  1. #include<iostream.h>

  2. void main()

  3. {

  4. int i=1,j=5;

  5. int& k=i;

  6. k=j; //語句[1]

  7. cout<<"i="<<i<<"; j="<<j<<"; k="<<k<<endl;

  8. }

首先想想程序運行結果應該是什麼呢?

VC6.0上運行後的結果是: 
i=5; j=5; k=5

分析: 
程序沒有錯誤,是正確的,但是並不能說明:引用能重新賦值。很明顯,引用是不能重新賦值的,只是理解上錯了! 
引用的賦值:是指引用初始化時,它的引用對象只能是變量,並且,一旦它指定爲某一個對象的引用後,就不能更改了。但是,可以用這個引用來改變它的對象的值,從而達到引用的目的——作爲變量對象的別名。 
如上例,引用k初始化爲i,即k從此以後一直是i的引用,若想讓k不再是i的引用而成爲別的變量的引用那是不可能的。所以,接下來的一句“k=j;”就不能理解成:取消k是i的引用而將k作爲j的引用。正確的理解應該是:利用引用k來改變它所指對象i的值,即相當於語句“k=5;”。若在上示例語句“k=j;”後加上一句“j=10”,結果將是:“i=5; j=10; k=5”,從這個結果就能很好理解了。 
所謂的引用的重新賦值,應該是: 
int x,y,z; 
int &x=y; 
&x=z; 
這種是對引用x,改變了它的指定對象,一開始是y的引用,之後,又重新說明是z的引用,這種引用的重新賦值是不允許的。

另外: 
常引用所引用的對象的值是不能更改的,即上述示例中若將語句“int& k=i;”更改爲“const int& k=I;”,則在編譯時就會出現錯誤了。??? 

不能const 引用應該說的是不能 int & const b = a; 因爲int &b 本就是int *const 類型,

可以const int &b = a;這樣後b就不能再賦值了。

其實可以這樣理解:

int &b = a;    -->  實質上是int *const  b  = &a;

引用的b是一個const 指針,第一次指向某個對象後,下次不能再&b = 另外一個對象,如果 b=c,實質是將a改變爲c,並不是重新指向對象。

 

https://blog.csdn.net/wanwenweifly4/article/details/6739687

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章