起源: 今天在瞭解反作用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語言初探 之 printf壓棧順序(printf("%d %d %d %d %d %d\n",a++, ++a, a++, ++a, a++, ++a ))