int a = 15;
printf("%d %d\n", ++a, a++);
老問題了,也沒什麼好說的,但是順序點涉及到參數的情況還沒仔細考慮過,所以分析下其內部原理。
我本來的考慮是按照 cdecl 壓棧次序,a++ 先壓入,為 15,此後++發生副作用,a 變為 16,然後壓入 ++a,a 先自增,為 17,所以輸出結果為 17 15。雖然心裡忐忑了一下,但也就這樣自欺欺人了一會,用 gcc 驗證無誤,然後 vc6 就給了我一棒子,它的輸出為 16 15。
說實話參數裡副作用的順序點我沒有研究過,所以導致了這個結果,於是好好看了下他們生產的彙編碼:
VC6相應彙編代碼:
5: int a = 15;
00401028 mov dword ptr [ebp-4],0Fh
6:
7: printf("%d %d\n", ++a, a++);
0040102F mov eax,dword ptr [ebp-4]
00401032 mov dword ptr [ebp-8],eax
00401035 mov ecx,dword ptr [ebp-8]
00401038 push ecx
00401039 mov edx,dword ptr [ebp-4]
0040103C add edx,1
0040103F mov dword ptr [ebp-4],edx
00401042 mov eax,dword ptr [ebp-4]
00401045 push eax
00401046 push offset string "%d %d\n" (00422020)
0040104B mov ecx,dword ptr [ebp-4]
0040104E add ecx,1
00401051 mov dword ptr [ebp-4],ecx
00401054 call printf (004010a0)
00401059 add esp,0Ch
可以看出,在 0x00401038 處,壓入了第三個參數為 15,0x0040103C 處 a++ 的副作用發生,a 變為 16;0x00401045 處壓入第二個參數為 16,直到 0x0040104E 處 ++a 的副作用才發生,輸出結果為 16 15。我感覺這裡的函數參數的逗號分隔字元並不是逗號運算式,所以不是一個順序點,導致 ++a 在這裡的副作用不一定發生,所以此時 vc 沒有增加 a 的值,是不是這樣呢?難道對於函數參數,順序點在函數結束處[待研究]?
再來看看 gcc 4.3 的情況,以下是同樣程式它的彙編碼:
0x00401146 <main+22>: movl $0xf,-0x8(%ebp)
0x0040114d <main+29>: mov -0x8(%ebp),%eax
0x00401150 <main+32>: addl $0x1,-0x8(%ebp)
0x00401154 <main+36>: addl $0x1,-0x8(%ebp)
0x00401158 <main+40>: mov %eax,0x8(%esp)
0x0040115c <main+44>: mov -0x8(%ebp),%eax
0x0040115f <main+47>: mov %eax,0x4(%esp)
0x00401163 <main+51>: movl $0x4020a0,(%esp)
0x0040116a <main+58>: call 0x4011d8 <printf>
可以看出,在 0x00401150 和 0x00401154 處 a 自增了 2 次,0x00401158 處壓入 printf 的第三個參數為 15,0x0040115f 處壓入第二個參數,而此時經過 0x0040115c,第二個參數已經為 17 了,所以結果為 17 15。
雖然是支末問題,不用糾纏,但是仍然引出了很多不確定的東西,當是學習了一次吧。