(i++)+(i++)与(++i)+(++i)

  • Post author:
  • Post category:其他


与在前面:++(–)有太多让人困惑的地方,(i++)+(i++)与(++i)+(++i)有什么不同?为什么不同?如果从机器的角度去理解,就会豁然开朗。

先来看段程序:


int


main()

{




int


i


=


3


;



int


j


=


(i


++


)


+


(i


++


);



//


int j=(++i)+(++i);





printf(





%d,%d\n





,i,j);

}


(1)在VC 6.0下:

对于(i++)+(i++):

结果:i=5,j=6

相应的汇编代码为(有详细注释):


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


对于(++i)+(++i):

结果:i=5,j=10

相应的汇编代码为:


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下:

对于(i++)+(i++):

结果:i=5,j=6相应的汇编代码为:



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


对于(++i)+(++i):

结果:i=5,j=10

相应的汇编代码为:



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


可见,对于VC6.0和gcc,二者的结果一致,但是gcc 3.2.2生成的汇编代码明显比VC6.0高效、简洁。这也许是因为VC 6.0出现较早的原因吧。


(3)如果这段代码用java实现,结果会怎样呢?

程序:


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。结果点意外!

来看看它的字节码吧:


//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


;


从栈中弹出两个int类型的数相加,结果入栈,即9入栈







11


:  istore_2


;


从栈中弹出9,存入j,即j=9

对于(i++)+(i++):

i=5,j=7。结果也很意外!

也来看看它的字节码吧:


//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没有入栈,所以此时栈中的数为3和4







10


:  iadd


;


从栈弹出两个int类型数相加,结果入栈,即7入栈







11


:  istore_2


;


从栈中弹出7,存入j,即j=7

Java与VC/gcc为什么会有如此的区别呢?其实原因很简单,VC/gcc生成的是本地代码,而X86处理器是基于寄存器的架构,也就是如果它要进行了两个数相加,它会先把两个数移到寄存器,再进行加法运算。而Java虚拟机是一种基于栈的架构,如果它要进行两个数相加,它会先弹出两个数,再进行加法运算,再将结果入栈。