熟悉掌握c++中函數調用堆棧,內存管理,智能指針
c++如何在程序運行時為程序調用內核堆棧的呢?
CPU是如何識別被調參數的呢?怎么保存傳遞的參數的呢?
所以cpu引進了棧的數據結構來完成函數的調用,函數調用時依次把參數壓棧,然后調用函數,
調用完以后從堆棧中取出數據並計算,計算結束后清棧
回想這個時先回想一下虛擬空間的空間布局和調用約定
int sum(int a,int b) { int tmp=0; tmp=a+b; return tmp; } int main() { int a=10; int b=20; int ret=0; ret=sum(a,b); Printf(“%d”,ret); } |
虛擬空間內存布局:1G內核空間,3G用戶空間
保留區 128M 不可讀不可寫 |
0x00000000 -- 0x0804 8000 |
.text 指令 |
|
.data |
|
.bss未初始化 |
(執行前清0) |
heap 堆 |
向下開辟 |
共享庫 |
|
stack 棧 |
向上開辟 |
環境變量 |
0xc000 0000 |
DMA |
|
NORMAL |
|
HIGHMEM |
0xffff ffff |
函數調用的具體情況:
Push 壓棧,pop 出棧,eax,ebx:存放數值
ebp:棧底指針寄存器esp:棧頂指針寄存器call:壓入下一行的指令地址
返回值:4字節 eax帶出,8 eax edx 》8 用臨時量帶回(在調用方棧幀開辟,臨時量在形參壓棧后壓棧)
具體實現如下:
0x0000 0000 esp |
tmp |
main函數的棧底指針 ebp |
下一條指令的地址 (&&printf) |
eax 10 |
eax 20 |
X X X X X X X X X X |
ret 0 |
b 10 |
a 20 |
mainCRTstartup函數的棧底指針 |
關於四種調用約定:
參數的傳遞中有兩個問題需要明確 約定符號的生成,形參的入棧順序(pasclcall),形參的開辟和清理方式
_cdecl:c標准調用約定 調用方開辟,調用方清除 如上
_stdcall:windows標准調用約定 自右向左入棧 調用方開辟,被調用方清除
_fastcall:快速調用約定 形參不開辟 在寄存器中存放 若形參個數過多的情況則
1)形參字節小於等於4 前兩個形參不開辟內存寄存器帶入被調用方 第三個開始和_stdcall調用約定相同
2)形參字節數大於4 和——stdcall相同,調用方開辟,被調用方清理
_thiscall:c++成員方法的調用約定 ,對參數個數不定的 調用者清棧,否則函數自己清棧
//匯編太麻煩了,你們可以自己去看看
c++是如何管理內存的呢?
大家都知道c語言在管理內存時候的方式:即上圖;其實c++的內存管理也是如此
那就說一下c++的幾種存儲結構吧(堆,棧,全局/靜態存儲區,文字常量區,text段)
棧:局部變量,參數,編譯器自動開辟釋放,相當於計算機系統的數據結構分配專門的寄存器來存儲棧的地址,所以效率較高,內存空間連續,但由於向下開辟,空間有限
堆:手動開辟釋放,向上開辟,內存空間無限制,內存不連續,會有內存碎片產生,具體的new和malloc以后會具體說明
全局/靜態存儲區:全局變量,靜態變量,程序結束時自動釋放,包括data段和bass段
文字常量區:存放在data段
text段:存放程序的二進制代碼