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


    与在前面:++(--)有太多让人困惑的地方,(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    11         ;i++, i=4
     5:   iload_1              ;将i压入栈,即4入栈
     6:   iinc    11          ; 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    11          ;i++,即i=4
     6:   iload_1               ;i入栈,即4入栈
     7:   iinc    11           ;i++,即i=5;注意:5没有入栈,所以此时栈中的数为3和4
     10:  iadd                  ;从栈弹出两个int类型数相加,结果入栈,即7入栈
     11:  istore_2            ;从栈中弹出7,存入j,即j=7

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

  • 相关阅读:
    数据系统与分布式(二) 分布式数据系统(复制与分片)
    数据系统和分布式(一)数据系统基础
    可执行文件(ELF)的装载与进程
    HTTPS协议
    后台开发 缓存, 数据库, 高并发等等
    Golang中new和make的区别
    吴恩达:机器学习里面的作业1遇到的
    笔记——操作系统导论:环境配置
    笔记——操作系统导论:第二章
    Games 101 作业1代码解析
  • 原文地址:https://www.cnblogs.com/hustcat/p/1494311.html
Copyright © 2020-2023  润新知