(i++)+(i++)与(++i)+(++i)
副标题#e#
与在前面:++(–)有太多让人狐疑的处所,(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呈现较早的原因吧。
#p#副标题#e#
(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。功效点意外!
来看看它的字节码吧:
#p#分页标题#e#
//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虚拟机是一种基于栈的架构,假如它要举办两个数相加,它会先弹出两个数,再举办加法运算,再将功效入栈。