C: printf參數執行順序與前置後置自增自減的影響

起源: 今天在瞭解反作用side-effect的過程當中,看到了下面的網頁,把我帶到了由printf引發的一系列問題,糾結了一成天,勉強弄懂。html

 

第一個代碼沒什麼好解釋的。而第二個printf("return of swap is %d\tx=%d,y=%d\n",swap(&x,&y),x,y)竟然是"return of swap is 1  x=1,y=0",輸出的x和y的值並無改變!ide

緣由在於C語言函數參數的處理是從右到左的壓棧順序(這個我在看第一個代碼時還不知道,由於第一個代碼從左往右操做的話,結果正好符合預期),但也跟編譯器有關(這個下面再說)。函數

此時的①理解時:先處理y,y爲0將0壓入棧,再處理x,x爲1將1壓入棧內,最後處理swap,值爲1將1壓入棧內,因此輸出的是110。post

但我以後又瀏覽到了有關自增自減與printf的問題,url

#include <stdio.h>
int main()
{
    int x;
    x=1;
    printf("%d %d\n",x,x++);  
    x=1;
    printf("%d %d\n",x++,x);  
    x=1;
    printf("%d %d %d\n",x,x++,x);  
    x=1;
    printf("%d %d %d %d\n",x,++x,x++,x);
    return 0;
}

 

按照①理解得出的答案應該是:spa

2 1.net

1 1指針

2 1 1code

3 3 1 1htm

但GCC編譯下來的結果是

2 1  

1 2  

2 1 2  

3 3 1 3

爲何要特指GCC下的結果呢,由於在後來的瀏覽中,發現,不一樣的編譯器會得出不一樣的結果(在第一個網頁裏有人就貼出了第一個代碼在vc6.0下的結果,沒重視,後來不斷有這類的信息出現,本身重裝了VC6.0才發現還真是不同!)。

在VC6.0下的:

1 1
1 1
1 1 1
2 2 1 1

這更邪乎了,在vc6.0裏後置符在printf裏都無論用了。

通過查閱得知,在GCC下,是先處理好全部參數,而後push,在遇到後置符時會當即輸出此時的值。

而VC6.0是處理好一個參數push一個且後置符在整條printf完成後纔會+1。

以這條爲例

x=1;
printf("%d %d %d %d\n",x,++x,x++,x);

 GCC下:

  處理x,此時x爲1。

  處理x++:temp = x, x = x + 1此時x爲2,temp爲1

  處理++x:x = x + 1,此時x爲3

  處理x,此時x爲3

  將x,temp,x,x壓入棧,而後一次彈出。結果爲3 3 1 3。但若是前置符是表達式中的一部分的話,則會輸出此時的值進行計算,例如:++x, ++x + 3,x(x初值是1)則輸出的是3 5 1而不是3  6 1

在VC6.0下:

  處理x,此時x爲1,壓棧。

  處理x++,此時x爲1,壓棧。

  處理++x,此時x爲2,壓棧。

  處理x,此時x爲2,壓棧。

  依次彈出,輸出結果爲2 2 1 1,而後處理x++,此時x爲3,即在後面加printf輸出x的值會輸出3。

但又有問題了,按照GCC的方式,則printf("return of swap is %d\tx=%d,y=%d\n",swap(&x,&y),x,y)因該是1 0 1啊,爲何x 和 y的值沒有換呢,難道是由於指針?

並且我又發如今進行指針處理後,以後在prinf中只有在該變量自增自減處理以後的才遵照上面GCC的操做,而在該變量自增自減處理以前的該變量則輸出當時的值。如:

#include <stdio.h>
int swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
    return 1;
}

int main()
{
    int x = 1, y = 1;
    printf("x = %d, y = %d\n", x, y);
    swap(&x, &y);
    printf("%d %d %d\n", x, ++x, x);
      return 0;
}

 

照着上面GCC的處理,則printf("%d %d %d\n", x, ++x, x)應輸出同樣的值2 2 2,但實際在GCC編譯後輸出的值是2 2 1。

我是完全搞混了,但最終的結論是:這跟編譯器如何處理有關(有人說是C/C++中未定義的行爲,因此不一樣編譯器有不一樣的操做),且在實際中不該該寫出這樣的代碼,重點是知道C中函數參數是從右到左的壓棧順序和自增自減是如何操做。

 

參考文章鏈接:

C語言的陷阱:關於函數參數的「反作用」問題

C語言初探 之 printf壓棧順序(printf("%d %d %d %d %d %d\n",a++, ++a, a++, ++a, a++, ++a ))

寫給初學者的有關printf("%d,%d,%d,%d\n", ++a,a++,--aa--);之類的表述

i++和++i做爲參數時的編譯器處理方式分析~

C語言詭異的printf函數

相關文章
相關標籤/搜索