棧是先入后出的數(shù)據(jù)結(jié)構(gòu).
渭城網(wǎng)站建設(shè)公司成都創(chuàng)新互聯(lián)公司,渭城網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為渭城上千家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\成都外貿(mào)網(wǎng)站制作要多少錢,請(qǐng)找那個(gè)售后服務(wù)好的渭城做網(wǎng)站的公司定做!
函數(shù)參數(shù)從右到左, 那么到函數(shù)內(nèi)部出棧的時(shí)候就是從左到右的順序了.
對(duì)于普通函數(shù)無區(qū)別. 但對(duì)于可變參函數(shù), 會(huì)根據(jù)左側(cè)參數(shù)來決定共計(jì)有多少參數(shù), 每個(gè)類型是什么.
比如 printf scanf這類的.
于是 就設(shè)計(jì)成從右到左的壓棧方式了.
因?yàn)橛行┦遣欢▍?shù)的
這樣函數(shù)內(nèi) 在處理的時(shí)候 從左到右 會(huì)更方便。
根據(jù)前面的參數(shù) 來確定后面還有多少參數(shù) 這樣。
要函數(shù)內(nèi)部彈棧從左到右
那么壓棧就只能從右到左了。
方法很簡(jiǎn)單:你講兩個(gè)棧都傳進(jìn)去,類似于 : int pus(SeqStack1 *s, DataType* x1, SeqStack2 *s, DataType* x2)(SeqStack1是你的第一個(gè)棧,SeqStack2是第二個(gè)棧,DataType是你需要傳進(jìn)去的數(shù)據(jù)的類型),然后在這個(gè)函數(shù)里面先判斷x1 ,x2是否為空,如果為空,則他對(duì)應(yīng)的那個(gè)棧不需要壓棧,如果不為空,則執(zhí)行相應(yīng)的壓棧操作。
不明白繼續(xù)追問!
i++是后+1,++i是先+1,多個(gè)參數(shù)的壓棧順序是從最后一個(gè)開始的因此,
上邊輸出的結(jié)果是第一行先++i,輸出就是2,后邊是I++,因此還是2;
第二行,先是i++,輸出就是1,之后++i,輸出就是2;
第三行,先是i++,輸出就是1,之后還是i++,輸出還是1,
但是本次取數(shù)完畢后,i已經(jīng)經(jīng)歷了2次+1變成了3了,因此第四行輸出的就是3
基本正確,補(bǔ)充一點(diǎn),參數(shù)一般是往寄存器里面放,放不下的情況下,才壓棧。
什么是堆和棧?
一個(gè)由c/C++編譯的程序占用的內(nèi)存分為以下幾個(gè)部分
1、棧區(qū)(stack)— 由編譯器自動(dòng)分配釋放 ,存放函數(shù)的參數(shù)值,局部變量的值等。其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧。
2、堆區(qū)(heap) — 一般由程序員分配釋放, 若程序員不釋放,程序結(jié)束時(shí)可能由OS回收 。注意它與數(shù)據(jù)結(jié)構(gòu)中的堆是兩回事,分配方式倒是類似于鏈表,呵呵。
3、全局區(qū)(靜態(tài)區(qū))(static)—,全局變量和靜態(tài)變量的存儲(chǔ)是放在一塊的,初始化的全局變量和靜態(tài)變量在一塊區(qū)域, 未初始化的全局變量和未初始化的靜態(tài)變量在相鄰的另一塊區(qū)域。 - 程序結(jié)束后有系統(tǒng)釋放
4、文字常量區(qū) —常量字符串就是放在這里的。 程序結(jié)束后由系統(tǒng)釋放
5、程序代碼區(qū)—存放函數(shù)體的二進(jìn)制代碼。
函數(shù)壓棧是怎么回事?
函數(shù)壓棧的本質(zhì)是參數(shù)傳遞
這又跟匯編語言連系起來了.匯編語言的過程即proc可以理解成函數(shù)
比如一個(gè)最簡(jiǎn)單的計(jì)算兩數(shù)之和函數(shù)
如果用匯編來寫估計(jì)是這樣的
sub proc
pop ax ;從stack取a 并放在AX寄存器中
pop bx ;從stack取b 并放在BX寄存器中
add ax,bx ; 計(jì)算a+b
ret //返回
sub endp
顯然要調(diào)用這個(gè)函數(shù),你應(yīng)當(dāng)先把b值push進(jìn)stack,然后再push a
因?yàn)閟tack是先進(jìn)后出的
所以調(diào)用匯編像這樣
比如計(jì)算4+5
push 5;
push 4;
call sub; //返回值在AX中
在這個(gè)例子中先壓5或先壓4得到的結(jié)果沒有變化
但大多數(shù)程序,如果參數(shù)的順序錯(cuò)誤將是災(zāi)難性的
因?yàn)椴还苁裁锤呒?jí)語言最終都要編譯成匯編語言,然后是機(jī)器語言
同樣下面這個(gè)C程序,計(jì)算a+b值,必然會(huì)編譯成上面的匯編代碼
int sub(int a ,int b) {return a+b;}
所以C在調(diào)用這個(gè)函數(shù)sub時(shí),必須要壓棧(即傳入?yún)?shù))但這些工作,在C語言里,并不需要你來完成.你只要寫出
sub(7,9);
編譯器在編譯成匯編時(shí)就會(huì)自動(dòng)完成相關(guān)的壓棧工作.
根據(jù)函數(shù)調(diào)用方式和參數(shù)壓入順序目前存在三種約定:
stdcall
cdecl
fastcall
這都相關(guān)壓棧順序和棧的清理工作約定
他們的細(xì)節(jié)都不相同,但有一點(diǎn)是肯定的,參數(shù)比須從右向左壓入棧中
stdcall中 函數(shù)必須自已清理?xiàng)?/p>
cdecall 由調(diào)用者清除堆棧 C的默認(rèn)函數(shù)調(diào)用方式 所以這樣C支持可變參數(shù)
fastcall 是把函數(shù)參數(shù)列表的前三個(gè)參數(shù)放入寄存器eax,edx,ecx,其他參數(shù)壓棧
源代碼:
int function(int a, int b)
{
return a + b;
}
void main()
{
function(10, 20);
}
1.__cdecl
_function
push ebp
mov ebp, esp
mov eax, [ebp+8] ;參數(shù)1
add eax, [ebp+C] ;加上參數(shù)2
pop ebp
retn
_main
push ebp
mov ebp, esp
push 14h ;參數(shù) 2入棧
push 0Ah ;參數(shù) 1入棧
call _function ;調(diào)用函數(shù)
add esp, 8 ;修正棧
xor eax, eax
pop ebp
retn
2.__fastcall
@function@8
push ebp
mov ebp, esp ;保存棧指針
sub esp, 8 ;多了兩個(gè)局部變量
mov [ebp-8], edx ;保存參數(shù) 2
mov [ebp-4], ecx ;保存參數(shù) 1
mov eax, [ebp-4] ;參數(shù) 1
add eax, [ebp-8] ;加上參數(shù) 2
mov esp, ebp ;修正棧
pop ebp
retn
_main
push ebp
mov ebp, esp
mov edx, 14h ;參數(shù) 2給EDX
mov ecx, 0Ah ;參數(shù) 1給ECX
call @function@8 ;調(diào)用函數(shù)
xor eax, eax
pop ebp
retn
3.__stdcall
_function@8
push ebp
mov ebp, esp
mov eax, [ebp] ;參數(shù) 1
add eax, [ebp+C] ;加上參數(shù) 2
pop ebp
retn 8 ;修復(fù)棧
_main
push ebp
mov ebp, esp
push 14h ;參數(shù) 2入棧
push 0Ah ;參數(shù) 1入棧
call _function@8 ;函數(shù)調(diào)用
xor eax, eax
pop ebp
retn