printf 函式壓棧方式

2021-06-20 01:55:53 字數 3444 閱讀 1802

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中,函式採用從右到左的壓棧方式,自己在退出時清空堆疊...