從彙編的角度看C 裡的引用和指標

2021-10-01 18:50:15 字數 2886 閱讀 2732

c++裡有引用和指標,使用過c++的應該都知道它們的異同點。本文將從彙編的角度去觀察這2者的本質。

使用也非常簡單,在左側編寫c++**,在右側就會直接顯示對應的組合語言,也可以根據需要的平台來選擇對應的編譯器

我們使用的c++**如下,比較簡單

int

main

(void

)

選擇的編譯器是x86_64 gcc-9.2,對應的彙編如下,

main:

push rbp

mov rbp, rsp

mov dword ptr [rbp-20]

,10lea rax,

[rbp-20]

mov qword ptr [rbp-8]

, rax

mov dword ptr [rbp-20]

,20mov rax, qword ptr [rbp-8]

mov dword ptr [rax],30

mov dword ptr [rbp-24]

,40lea rax,

[rbp-24]

mov qword ptr [rbp-16]

, rax

mov dword ptr [rbp-24]

,50mov rax, qword ptr [rbp-16]

mov dword ptr [rax],60

mov eax,

0 pop rbp

ret

大家對彙編可能不太熟悉,本人也是一樣,雖然以前自學過彙編(王爽的《組合語言》),但是都忘光了。因為這裡的c++程式比較簡單,所以對應的彙編也比較簡單,講解前,可以先簡單看下下面這幅x86-64通用暫存器表,

在看彙編時可以回頭看看下上面的暫存器表

1. 開頭2行

push    rbp

mov rbp, rsp

這裡用到了rbp暫存器,這個暫存器在上面那張表裡說是被呼叫者保護,有點懵,可以理解為資料儲存,在這裡用來存放堆疊指標。由於main函式也是乙個函式,也是被呼叫才會執行的,呼叫函式時,會先把此時的堆疊指標值壓棧,這樣當從被呼叫函式返回時可以回到呼叫函式的那個點

2. 結尾三行

mov     eax,

0pop rbp

ret

這個比較簡單,就在eax裡存入返回值,然後把開頭存放的堆疊指標值出棧,然後函式返回,這樣就會返回到呼叫函式的那個點

3. 引用操作對應的彙編

mov     dword ptr [rbp-20]

,10lea rax,

[rbp-20]

mov qword ptr [rbp-8]

, rax

mov dword ptr [rbp-20]

,20mov rax, qword ptr [rbp-8]

mov dword ptr [rax]

,30

解析:4. 指標操作對應的彙編

mov     dword ptr [rbp-24]

,40lea rax,

[rbp-24]

mov qword ptr [rbp-16]

, rax

mov dword ptr [rbp-24]

,50mov rax, qword ptr [rbp-16]

mov dword ptr [rax]

,60

通過比較發現,指標操作對應的彙編**和引用是一樣的…

本文從彙編**上去觀察c++的引用和指標,可以看出他們最終的本質都是一樣的,只是在c++語法層面有所區別,並且應用場景也是不同的,具體可以看《c++ primer 5th》。

本來之父也和你一樣想的,有指標就夠了,一樣能實現相應的功能,沒必要再多乙個語法設施。但後來為了加運算子過載,沒有引用的話,前自增的語義就難以說明清楚,這是引入引用概念的歷史背景。後來你可以發現,線性容器所過載的下標運算子,迭代器和智慧型指標所過載的間接訪問運算子,輸入流和輸出流的鏈式呼叫,這一切都是離不開引用語義的。

拋開運算子過載的歷史因素,引用在大多數場合下完全可以視作指標的語法糖——在底層的彙編的層面講他們是一樣實現的。不過有了引用以後,確實寫**可以方便很多。比如最常見的手法就是利用引用免掉一階的指標。在 c 裡面,你要在函式中修改乙個一級指標,形參裡得宣告成二級指標,但在 c++ 裡形參宣告成一級指標的引用就可以了。別看只是降了一階,但人類的思維理解高維的概念很困難,問題降一階以後考慮問題就可以輕鬆很多。

有了引用以後,**也變得簡練。以前在 c 裡,如果要設計乙個函式處理大物件,則不得不以指標做引數,那就不得不宣告臨時變數去儲存中間結果。

matrix a, b, c; getmatrixa(&a); getmatrixb(&b); addmatrix(&a, &b, &c); printmatrix(&c);

而在 c++ 裡,則完全不需要考慮這些,完全可以以引用當引數,**又清晰,又不用擔心會拷貝而帶來效率瓶頸。

print(addmatrix(getmatrixa(), getmatrixb()));

從彙編角度看引用

引用型別到底是什麼?它和指標有什麼關係?它本身占用記憶體空間嗎?帶著這些疑問,我們來進行分析。先看 include include using namespace std void main 通過彙編檢視 如下 9 int x 1 00401048 mov dword ptr ebp 4 1 10 ...

彙編角度看指標和引用的區別

一 定義上來看 引用是變數的別名,指標是指向變數的位址。引用不可以為空但是指標可以為空,所以引用必須在定義的時候必須初始化並且初始化後不能被改變引用的物件,但是指標可以該變自己的指向。引用必須引用有記憶體位址的量,如果是引用常量的話,必須使用常引用。常引用的實現方法是編譯器為常量開闢乙個臨時量的記憶...

從彙編看C 中的指標和引用

以前寫c 的時候,我認為指標是就是乙個存著另乙個變數位址的變數,他是有儲存空間的,而引用只是乙個變數的別名,不會占用儲存空間。最近在搞彙編,發現下面兩段 的生成的彙編 是一樣的 指標 void func 引用 void func 上面兩段 的生成的彙編都是 004019d0 push ebp 004...