c語言,c++函式呼叫壓棧方式取決與編譯器。
但是一般編譯器是右序壓棧的。
下面介紹一下c 語言是如何右序壓棧的:
如下函式:
#include
int main()
一般人會認為輸出結果是:
3,4 5
可是實際結果卻是:
4,3 5
為什麼呢,原因就取決於c 語言的函式壓棧方式是右序的。
在比如有 int x=2 , y=1 printf("%d,%d", x+y, x-y);
那麼該如何執行呢,下面我們來分解一下:
執行printf過程中:(1) 執行x-y 得到1 , (2)執行x+y 得到3;
(3) 從右向左依次入棧,即:x-y 得到的 1 先入棧 , x+y得到的3 後入棧
(4) 依次出棧輸出:3,1
說到這裡大家應該都明白右序入棧的情況了吧。
5 在此大家還應該注意先加後加的問題;這個問題我在此就不多贅述了。
另外,在c++中情況和這個類似,c++ 中cout 和c語言中的printf情況類似。
關於cout
和printf
問題:#include
using namespace std;
int rolc = 0;
int f1()
int main()
在看上面的程式,一般想當然會輸出:
in f1() 0:
0in f2() 1:
1press any key to continue
可實際結果不是這樣的,在vc++ 6.0
執行結果如下:
in f2() 0:
in f1() 1:10
press any key to continue
為何是這樣呢?原因:標準未指定函式引數的求值順序所導致的。具體分析如下:
c/c++在函式呼叫時,預設都是右序入棧,這肯定是沒有錯的。如果不是右序入棧的函式,必須以其它關鍵字指明
,比如pascal
關鍵字。但是,這裡不光涉及到引數的入棧順序,還涉及到以表示式做為函式引數時,表示式的求值
順序。看這個例子:
如果有這樣乙個函式:
int max(int a, int b);
我這樣呼叫它:
int x = 10;
int y = 6;
int z = max(x, y);
生成**時,必然是y
先入棧,然後
x入棧,再
call max
。這就是右序入棧,
c/c++
的預設方式。
但是,如果在呼叫時,以表示式做為引數,又會怎麼樣呢?看下面
int z = max(x - y, x + y);
要知道,在呼叫max
的時候,不可能把
x + y
這樣的整個表示式入棧,必須求出表示式的值,然後將表示式的值做為
函式呼叫的引數入棧。可是,這裡有兩個表示式:x-y
和 x+y
,那麼先應該求
x-y的值,還是先求出
x+y的值?
c/c++語言都沒有規定這個順序,編譯器實現可以自己定義。也就是說,乙個編譯器,可以先求出
x+y的值,再求
x -y的值,然後將
x+y的值入棧,然後再將
x-y的值入棧,呼叫
max。也可以先求出
x-y的值,再求
x+y的值,然後將
x+y 值入棧,然後再將x-y
的值入棧,呼叫
max。 引數求值順序不定,但是引數入棧順序確定。
看下面的例子:
cout << "ljgajagj";
這相當於operator << (cout, "ljgajagj");
這兩句是完全相同的,只是不同的寫法而已。在呼叫時,
"ljgajagj"
的位址先入棧,然後cout
入棧,然後呼叫
operator <<
,最終的結果就是輸出字串
"ljgajagj"
。 看下面的例子:
cout<<" ljgajagj"《這相當於operator<<( operator << (cout, "ljgajagj") , endl);
紅色部分,以乙個函式呼叫的形式,做為最外面的operator <<()
的第乙個引數。最外面的
operator<<
有兩個引數
,其中乙個是表示式,所以先要對此表示式求值, 也就是先呼叫裡面的operator << (cout, "ljgajagj")
部分 ,輸出字串,然後將endl
入棧,然後將
operator << (cout, "ljgajagj")
的返回值,也就是乙個
cout
物件入棧
,然後呼叫外面的operator<<()
。這樣,肯定是先輸出字串,而不會先輸出
endl
。 下面看上面提出的問題,因為最後的endl
不影響結果,所以,為了方便,忽略最後的
endl
,簡化成下面的形式:
cout《對於最外面的operator <<()
,有三個引數,且有三個引數都是表示式,所以要分別對三個表示式求值,可是對三個表示式的求值順序是不一定的。
如果是左序,1.
呼叫f1()
求值,輸出字串
"in f1() 0:"
,2.呼叫
operator << (cout, "\n")
求值,得到
cout
物件3.呼叫
f2()
求值,輸出字串
"in f2() 1:"
4.將f2()
返回值、
cout
物件、f1()
返回值入棧
5.呼叫最外面的
operator<<()
輸出in f1() 0:
in f2() 1:01
press any key to continue
如果是右序,1.
呼叫f2()
求值,輸出字串
"in f2() 0:"
,2.呼叫
operator << (cout, "\n")
求值,得到
cout
物件3.呼叫
f1()
求值,輸出字串
"in f2() 1:"
4.將f2()
返回值、
cout
物件、f1()
返回值入棧
5.呼叫最外面的
operator<<()
輸出in f2() 0:
in f1() 1:10
press any key to continue
printf 函式的壓棧問題
我們經常會在程式設計中用到printf這個函式,對於這個函式與scanf函式有相似的地方 或者說是有聯絡 首先我們要先從scanf函式的引數入棧說起,一般ide來說 對c語言 入棧的順序是從右往左進行壓棧 事例一 壓棧相關的簡單例子,如下 include main 那麼這個輸入會是多少呢?我用dev...
printf函式的引數壓棧問題
最近看到一些程式設計師的筆試題目,經常會考到printf函式的引數壓棧問題,總體來講就是引數從右向左依次壓棧,再出棧,但是今天看到乙個看似很簡單的題目,卻一直找不到頭緒。題目如下 cpp view plain copy include void main 輸出看似很簡單,但是結果卻打出所料。輸出是 ...
關於函式壓入棧的幾種方式
被這些修飾關鍵字修飾的函式,其引數都是從右向左通過堆疊傳遞的 fastcall的前面部分由ecx,edx傳 函式呼叫在返回前要清理堆疊,但由呼叫者還是被呼叫者清理不一定。1 stdcall是pascal程式的預設呼叫方式,通常用於win32 api中,函式採用從右到左的壓棧方式,自己在退出時清空堆疊...