前言
好久沒寫東西了,突發奇想,寫寫函數參數的壓棧順序
先看看這個問題
https://q.cnblogs.com/q/137133/
然后看我簡化的代碼,猜輸出結果是多少?
#include<bits/stdc++.h>
using namespace std;
int main(){
int i=0;
printf("%d %d",i++,i--);
return 0;
}
根據++和--的特性,i++的時候數值不變,輸出0,i--時i才加上1,輸出1。
事實是這樣嗎?我在多台編譯器上執行,輸出的結果都是:
-1 0
棧
根據我之前寫過的指針篇的內容,函數的局部變量保存在棧中,都是獨立的,參數同樣保存在棧中,才導致了swap函數改變函數參數必須使用指針。
那么,函數參數,在棧中是如何排列的呢?順序?倒序?
我們寫一個簡短的代碼,來實驗一下。
#include<bits/stdc++.h>
using namespace std;
void test(int a,int b){
printf("a..%p, b..%p",&a,&b);
}
int main(){
int a,b;
test(a,b);
}
由於是地址,不同編譯器的結果不同。但肯定的是,a比b大4。
如果多加幾個變量進去,我們發現,地址的大小從大到小遞減。
棧模型
圖源:《征服C指針》
從這張圖中可以看出,C語言中,參數是從后往前堆積在棧中的。這種處理方式的好處在於,無論有多少個參數,總能找到第一個參數的地址,這樣就可以順次找到后面的參數。否則,從后往前,就無法找到第一個參數,也無法實現可變長參數的功能。
例如在printf中,我們找到第一個參數的位置,例如"%d %s",就可以順次解析后面的地址的參數,因為參數是連續在內存排列的。
問題解釋
既然參數是從后往前放入棧中的,那么,我們就可以解釋這個問題了。
#include<bits/stdc++.h>
using namespace std;
int main(){
int i=0;
printf("%d %d",i++,i--);
return 0;
}
開頭的代碼。如果編譯成匯編語言進行執行,應該是這個樣子(如果有錯誤請指正,手寫的)
sub [i],1 ;i--
push [i]
add [i],1 ;i++
push [i]
push offset string "%d %d" ;"%d %d"
call dword ptr_printf ;調用printf
在匯編語言中,push是將參數壓入棧的一個指令,由於這篇文章不是講匯編的,大家看看就好。
因此,在推入棧的時候,先執行了i--,再執行i++,結果也當然是這樣了。