int main() {
int i = 3;
int j = (i++) + (i++);
// int j = (++i) + (++i);
printf("%d,%d\n", i, j);
}
結果:i=5, j=6
mov eax, [ebp-4] ; i → eax (3)
add eax, [ebp-4] ; eax = i+i = 6
mov [ebp-8], eax ; j = 6
mov ecx, [ebp-4] ; i → ecx (3)
add ecx, 1 ; ecx = 4
mov [ebp-4], ecx ; i = 4
mov edx, [ebp-4] ; i → edx (4)
add edx, 1 ; edx = 5
mov [ebp-4], edx ; i = 5
關鍵點:先用原值 i 計算加法(3+3=6),再做兩次後置遞增。
結果:i=5, j=10
mov eax, [ebp-4] ; i → eax (3)
add eax, 1 ; eax = 4
mov [ebp-4], eax ; i = 4
mov ecx, [ebp-4] ; i → ecx (4)
add ecx, 1 ; ecx = 5
mov [ebp-4], ecx ; i = 5
mov edx, [ebp-4] ; i → edx (5)
add edx, [ebp-4] ; edx = 10 (i+i)
mov [ebp-8], edx ; j = 10
關鍵點:先做兩次前置遞增(i 變 5),再用新值計算加法(5+5=10)。
與 VC6.0 完全一致:(i++)+(i++) → i=5,j=6;(++i)+(++i) → i=5,j=10。GCC 產生的彙編更精簡高效。
public class TestAdd {
public static void main(String[] args) {
int i = 3;
int j = (i++) + (i++); // 5, 7
// int j = (++i) + (++i); // 5, 9
System.out.println(i + "," + j);
}
}
(++i)+(++i) → i=5, j=9
iconst_3 ; 3 入棧
istore_1 ; i=3
iinc 1, 1 ; i=4
iload_1 ; 壓入 4
iinc 1, 1 ; i=5
iload_1 ; 壓入 5
iadd ; 彈出 4,5 → 9 入棧
istore_2 ; j=9
(i++)+(i++) → i=5, j=7
iconst_3 ; 3 入棧
istore_1 ; i=3
iload_1 ; 壓入 3
iinc 1, 1 ; i=4
iload_1 ; 壓入 4
iinc 1, 1 ; i=5 (注意:5 未入棧)
iadd ; 彈出 3,4 → 7 入棧
istore_2 ; j=7
| 特性 | x86 本地代碼 (VC/GCC) | JVM 字節碼 |
|---|---|---|
| 架構 | 寄存器式 | 棧式 |
| 運算方式 | 將操作數移至寄存器再運算 | 從棧彈出操作數運算後壓回 |
| 副作用可見性 | 內存/寄存器即時更新 | 棧中保存的是「讀取時的值」,後續遞增不影響棧中舊值 |
C/C++ 標準規定:同一序列點修改同一對象多次,行為未定義。上述結果僅反映特定編譯器/JVM 的實現細節,**不可依賴**。
int a = i++; int b = i++; j = a + b;/Wall、-Wsequence-point)捕獲此類代碼