您的位置:首页 > 其它

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

2016-04-06 13:38 281 查看
与在前面:++(--)有太多让人困惑的地方,(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虚拟机是一种基于栈的架构,如果它要进行两个数相加,它会先弹出两个数,再进行加法运算,再将结果入栈
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: