與在前面:++(--)有太多讓人困惑的地方,(i++)+(i++)與(++i)+(++i)有什么不同?為什么不同?如果從機(jī)器的角度去理解,就會(huì)豁然開(kāi)朗。
先來(lái)看段程序:
int main()
{
int i=3;
int j=(i++)+(i++);
// int j=(++i)+(++i);
printf("%d,%d\n",i,j);
}
(1)在VC 6.0下:
對(duì)于(i++)+(i++):
結(jié)果:i=5,j=6
相應(yīng)的匯編代碼為(有詳細(xì)注釋):
8B 45 FC mov eax,dword ptr [ebp-4] ;i->eax
03 45 FC add eax,dword ptr [ebp-4] ;i+i=6
89 45 F8 mov dword ptr [ebp-8],eax ;6->j
8B 4D FC mov ecx,dword ptr [ebp-4] ;i->ecx(=3)
83 C1 01 add ecx,1 ;ecx=4
89 4D FC mov dword ptr [ebp-4],ecx ;4->i
8B 55 FC mov edx,dword ptr [ebp-4] ;i->edx
83 C2 01 add edx,1 ;edx=5
89 55 FC mov dword ptr [ebp-4],edx ;5->i
對(duì)于(++i)+(++i):
結(jié)果:i=5,j=10
相應(yīng)的匯編代碼為:
8B 45 FC mov eax,dword ptr [ebp-4] ;i->eax (=3)
83 C0 01 add eax,1 ;eax=4
89 45 FC mov dword ptr [ebp-4],eax ;4->i
8B 4D FC mov ecx,dword ptr [ebp-4] ;i->ecx
83 C1 01 add ecx,1 ;ecx=5
89 4D FC mov dword ptr [ebp-4],ecx ;5->i
8B 55 FC mov edx,dword ptr [ebp-4] ;i->edx
03 55 FC add edx,dword ptr [ebp-4] ;edx=10 ,即i+i
89 55 F8 mov dword ptr [ebp-8],edx ;10->j
(2)在gcc 3.2.2下:
對(duì)于(i++)+(i++):
結(jié)果:i=5,j=6相應(yīng)的匯編代碼為:
c7 45 fc 03 00 00 00 movl $3, -4(%ebp) ;3->i
8b 55 fc movl -4(%ebp), %edx ;i->edx (=3)
8b 45 fc movl -4(%ebp), %eax ;i->eax (=3)
8d 04 10 leal (%eax,%edx), %eax ;i+i=6 ->eax
89 45 f8 movl %eax, -8(%ebp) ;6->j
8d 45 fc leal -4(%ebp), %eax ;&i->eax
ff 00 incl (%eax) ;i++ ,即i=4,注意這里為寄存器間接尋址
8d 45 fc leal -4(%ebp), %eax ;&i->eax
ff 00 incl (%eax) ;i++,即i=5
對(duì)于(++i)+(++i):
結(jié)果:i=5,j=10
相應(yīng)的匯編代碼為:
movl $3, -4(%ebp) ;3->i
leal -4(%ebp), %eax ;&i->eax
incl (%eax) ;i++,即i=4
leal -4(%ebp), %eax ;&i->eax
incl (%eax) ;i++, i=5
movl -4(%ebp), %eax ;i->eax, eax=5
addl -4(%ebp), %eax ;i+i ->eax ,eax=10
movl %eax, -8(%ebp) ;10->j
可見(jiàn),對(duì)于VC6.0和gcc,二者的結(jié)果一致,但是gcc 3.2.2生成的匯編代碼明顯比VC6.0高效、簡(jiǎn)潔。這也許是因?yàn)閂C 6.0出現(xiàn)較早的原因吧。
(3)如果這段代碼用java實(shí)現(xiàn),結(jié)果會(huì)怎樣呢?
程序:
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);
}
}
對(duì)于(++i)+(++i):
i=5,j=9。結(jié)果點(diǎn)意外!
來(lái)看看它的字節(jié)碼吧:
//j=(++i)+(++i)
//5,9
0: iconst_3 ;常量3入棧
1: istore_1 ;從棧中彈出3,存入i,i=3
2: iinc 1, 1 ;i++, i=4
5: iload_1 ;將i壓入棧,即4入棧
6: iinc 1, 1 ; i++,i=5
9: iload_1 ;i入棧,即5入棧
10: iadd ;從棧中彈出兩個(gè)int類型的數(shù)相加,結(jié)果入棧,即9入棧
11: istore_2 ;從棧中彈出9,存入j,即j=9
對(duì)于(i++)+(i++):
i=5,j=7。結(jié)果也很意外!
也來(lái)看看它的字節(jié)碼吧:
//j=(i++)+(i++)
//5,7
0: iconst_3 ;常量3入棧
1: istore_1 ;從棧中彈出3,存入i,i=3
2: iload_1 ;i入棧,即3入棧
3: iinc 1, 1 ;i++,即i=4
6: iload_1 ;i入棧,即4入棧
7: iinc 1, 1 ;i++,即i=5;注意:5沒(méi)有入棧,所以此時(shí)棧中的數(shù)為3和4
10: iadd ;從棧彈出兩個(gè)int類型數(shù)相加,結(jié)果入棧,即7入棧
11: istore_2 ;從棧中彈出7,存入j,即j=7
Java與VC/gcc為什么會(huì)有如此的區(qū)別呢?其實(shí)原因很簡(jiǎn)單,VC/gcc生成的是本地代碼,而X86處理器是基于寄存器的架構(gòu),也就是如果它要進(jìn)行了兩個(gè)數(shù)相加,它會(huì)先把兩個(gè)數(shù)移到寄存器,再進(jìn)行加法運(yùn)算。而Java虛擬機(jī)是一種基于棧的架構(gòu),如果它要進(jìn)行兩個(gè)數(shù)相加,它會(huì)先彈出兩個(gè)數(shù),再進(jìn)行加法運(yùn)算,再將結(jié)果入棧。