C 返回區域性變數引用的具體細節

2021-10-06 19:49:01 字數 3359 閱讀 9673

書上都說不能返回區域性變數的引用或區域性指標,說這種行為危險,但又沒講具體原因,那麼今天就來看看這種行為的具體細節

ps:下面含有at&t彙編內容,未學過彙編的朋友可以跳過直接看結論

先放乙個實驗用函式,即返回int&型別的區域性變數的函式

int

&retint()

稍後會用到的幾個測試函式,用來說明不同情況下使用區域性的結果

void

nop(

)void

snop()

void

skip()

主函式如下(待會使用控制變數法)

呼叫nop函式

/**

* @brief filename:main.cpp

* environment : g++&ubuntu18.04

*/int

main()

$ g++ main.cpp -omain;./main #編譯指令
輸出結果為:

4242

即兩次使用返回的區域性變數引用都表現正常

這時候回顧前瞻知識:

區域性變數存放在棧區

區域性變數使用後會被銷毀(棧頂指標變化)

引用為變數別名,實際編譯中仍會取變數位址(可見下面源程式和彙編相應部分)

int  i=42;

int& iref=i;

int* ip=

&i;

movl    $42, -36(%rbp)      ;int i=42;

leaq -36(%rbp), %rax ;leaq 為彙編取位址操作

movq %rax, -32(%rbp) ;int& iref=i;//可見引用佔的大小和 型別(int)大小是相同的

leaq -36(%rbp), %rax

movq %rax, -24(%rbp) ;int* ip=&i;//指標為 8 個 位元組

解釋

引用存放位址不與變數存放位址相同

銷毀物件並不會改變相應位址的值,只改變棧頂指標,所以值能很容易被重寫,但目前沒有資料去重寫這塊位址的值

連續宣告兩個變數的位址在之後(即沒有覆蓋)

下面看一下彙編的具體細節

main函式

黃框部分為c++原始檔中函式語句直接對應部分

可以看到之前函式所用記憶體:-20(%rbp) -16(%rbp) 是沒有改變的

呼叫snop函式

編譯指令不變

輸出結果:

這時似乎可以懷疑是int i=retint();時,這時的 i 已經是3了

那麼修改了一下main函式

結果不變,和上面是一樣啊

到這裡就基本驗證了之前的解釋

只宣告變數的函式未覆蓋之前銷毀的物件位址

而如果使用了引用則覆蓋位址

呼叫skip函式

編譯指令不變

輸出結果:

42

1074842828

skip函式中常量引用 d 的值改為 0.0 後,輸出第二行為 0

如果第二次實驗只是改變了數值,還勉強能看到值的由來的話,那這個 4.2 帶來的值的變化,是著實看不懂了

其實的話,是用double型別浮點數的形式儲存 4.2 然後用int型別的形式去讀取相應記憶體單元的結果

可以看出顯示的是skip函式定義的常量引用的高位位址的值

也許會有人質疑double型別的會影響是因為double 八位,相當於 int 與 int& 的總和

於是對skip函式稍加更改

輸出結果:

42

4

retint 函式的彙編沒有變化

可以看到依然發生了對位址的覆蓋改寫

實驗結果是對書所說結果的驗證。

銷毀物件的意思是可以改寫那一塊的值。

區域性變數引用的使用是有很大風險的

1. 風險在於所使用的引用的值,可能發生意味的改變使用者不知道或未注意到的

2. 除非是當臨時值使用 如同std:cout<

其實看著彙編**來說的話 原來那個位置的值還是可以算出來的 能通過看**最後知道那個值

1. 不過 正經人誰做這個

簡單點說就是 理解這種情況就相當於

int

retref()

intmain()

補充一點就是 返回指向區域性變數的指標跟這個是差不多

不能返回區域性變數的引用

源之 int add1 int a,int b int add2 int a,int b 請問這兩個函式返回有什麼區別,是乙個返回副本,另乙個直接返回嗎?呼叫函式add2有什麼危險嗎?add1的確返回了乙個副本,如果sum是自定義的類型別,可以很明顯看出拷貝建構函式在返回時被呼叫,對於內建型別沒什麼...

千萬不能返回區域性變數的引用??

c primer第7章函式一節,講到返回時,理解返回引用至關重要的是,千萬不能返回區域性變數的引用 意思是返回程式內部定義的變數時可能會出問題,因為當函式執行完畢後,將釋放分配給區域性物件的儲存空間。此時,對區域性物件的引用就會指向不確定的記憶體。覺得不能理解。比如求階乘時,可以使用迭代函式的方法,...

引用與區域性變數的返回問題

今天剛相對徹底的搞懂函式返回區域性普通變數 不包括指標和引用 與區域性指標 引用的返回區別,先看下面 include include using namespace std string version1 const string s1,const string s2 const string ve...