浅谈前置++和后置++的区别

       最近有个刚学编程的小妹妹问我关于*p++(p为指针)的运算过程,这两操作符优先级一样,且从右到左

 

行。大都初学者会这样认为,p指针先执行++操作,然后再执行*操作。可是结果返回的却是p指针的一开

 

指向的值,而并不是++后指向的值。  

 

       这就涉及到前++和后++一些运算的逻辑了。

 

 

         下面我将通过汇编代码来简单的讲下它们的区别。

 

        下面是c代码:

     

      并附上汇编代码:

     

 

 

      我们从int m = 3开始分析,大家可以看到在汇编中,

 

通过 mov 操作把 3传入dword prt [m]中,


      对于m++和++m,它们的指令是一样的,都是先把内存 dword ptr [m]中的值传入eax寄存器,然后进

 

行自增操作,最后传回内存 dword ptr [m] 中。

 

     下面我们主要讲下 x = (++m)+(++m)+(++m);和y = (m++)+(m++)+(m++);

 

      1. x = (++m)+(++m)+(++m);代码中此时m = 5;

     

      对于大多数初学者来说,或者刚认识前++和后++来的人说,会觉得x = 6 + 7 + 8= 21

 

      可是事实却非如此。看汇编源码:

      00E313B7  mov         eax,dword ptr [m]  //把内存 dword ptr [m]的值(5)传入 寄存器eax中
      00E313BA  add          eax,1                     //寄存器自增1
      00E313BD  mov         dword ptr [m],eax  //在把寄存器eax中的值(6)传回内存
dword ptr [m]中
      00E313C0  mov         ecx,dword ptr [m]  // 把内存 dword ptr [m]的值(6)传入 寄存器ecx中
      00E313C3  add         ecx,1                      //寄存器自增1
      00E313C6  mov         dword ptr [m],ecx  //在把寄存器ecx中的值(7)传回内存 dword ptr [m]中
      00E313C9  mov         edx,dword ptr [m]  // 把内存 dword ptr [m]的值(8)传入 寄存器edx中
      00E313CC  add         edx,1                      //寄存器自增1
      00E313CF  mov         dword ptr [m],edx  //在把寄存器ecx中的值(8)传回内存 dword ptr [m]中

     首先我们的编译器用3个寄存器(eax,ecx,edx)来计算m的三次自增,而不是初学者想的先计算第一

 

个++m,然后算出括号中的值为4.

 

      接着编译器 再执行3个+操作 ,汇编代码如下:

     00E313D2  mov         eax,dword ptr [m]  // 把内存 dword ptr [m]的值(8)传入 寄存器eax中
     00E313D5  add         eax,dword ptr [m]  // 把内存 dword ptr [m]的值(8)与 寄存器eax中的值相加     

                                                                     结果保存在eax中则为(16)
     00E313D8  add         eax,dword ptr [m]  // 把内存 dword ptr [m]的值(8)与 寄存器eax中的值相加     

                                                                     结果保存在eax中则为(24)


     00E313DB  mov         dword ptr [x],eax  //在把寄存器eax中的值(24)传回内存 dword ptr [m]中

 

     因此x = 8 + 8 + 8 = 24;

 

    2. y = (m++)+(m++)+(m++); 代码中此时m = 8;

 

     对于这行代码,大都初学者会觉得y = 8 + 9 + 10 = 27;


      可是结果也让大家大跌眼镜,看汇编代码:

     00E313FD  mov         eax,dword ptr [m]  / / 把内存 dword ptr [m]的值(8)传入 寄存器eax中
     00E31400  add         eax,dword ptr [m]   / / 把内存 dword ptr [m]的值(8)与 寄存器eax相加的(16)
     00E31403  add         eax,dword ptr [m]   / / 把内存 dword ptr [m]的值(8)与 寄存器eax相加的(24)
     00E31406  mov         dword ptr [y],eax   //把寄存器eax的值(24)传给内存 dword ptr [y]

     从这可以看出,编译器是先进行+操作,然后再运算下面那3个++操作
     00E31409  mov         ecx,dword ptr [m] 
     00E3140C  add         ecx,1 
     00E3140F  mov         dword ptr [m],ecx 
     00E31412  mov         edx,dword ptr [m] 
     00E31415  add         edx,1 
     00E31418  mov         dword ptr [m],edx 
     00E3141B  mov         eax,dword ptr [m] 
     00E3141E  add         eax,1 
     00E31421  mov         dword ptr [m],eax

     以上测试只是在VC上做的操作,可能初学者可能看到过为什么不同编译器会出现不同的结果呢,这个

 

就是得看编译器怎样处理这种像连续对一个变量进行++操作了。

    

     以上测试并不是来说明这种类似的语句就是这样的运算方式,只是对于感兴趣的人看看这些代码在VC

 

上是如何运行的,一般来说,我们是静止写出这种代码的,因为这种代码对编译器依赖性比较大。不同的

 

编译器有不同的解析方法。

 

 

     接下来我来谈谈小妹妹的问题,对于*p++和*++p编译器是如何操作的,

   

    c源码如下:

     

 

      汇编代码:

    

 

 

    我们从int a[] = {1,2,3,4,5};开始
    001913A8  mov         dword ptr [ebp-1Ch],1   //a
    001913AF  mov         dword ptr [ebp-18h],2   //a+1
    001913B6  mov         dword ptr [ebp-14h],3   //a+2
    001913BD  mov         dword ptr [ebp-10h],4   //a+3
    001913C4  mov          dword ptr [ebp-0Ch],5  //a+4

 

    接着

              int *p = a;
    002113CB  lea         eax,[ebp-1Ch]    //把[ebp-1Ch]的偏移地址取出来,放入eax
    002113CE  mov         dword ptr [ebp-28h],eax 
//[ebp-28h]是int *p语句产生的开辟的一个额外的 

                                                         内存,它保存的是 [ebp-1Ch]的偏移地址,也就是a 的偏移地址。

              int b = *p++;
    002113D1  mov         eax,dword ptr [ebp-28h]  //先把内存
dword ptr [ebp-28h]保存的值也就是a

                                                                            的偏移地 址传入eax寄存器中
    002113D4  mov         ecx,dword ptr [eax]         //通过dword ptr [eax] 操作把eax保存的值也就是a的偏移地址从新当做内存的地址,并通过这个偏移地址把该内存中的值(也就是a[0])取出来传入ecx寄存器
    002113D6  mov         dword ptr [ebp-34h],ecx  //把ecx的值(a[0])传入内存
dword ptr [ebp-34h]

                                                                            // dword ptr [ebp-34h]为变量b的内存
    002113D9  mov         edx,dword ptr [ebp-28h] //把内存 dword ptr [ebp-28h]保存的值(a的偏移地

                                                                            址) 传入edx寄存器中
    002113DC  add         edx,4                              //因为指针的是由4个字节组成的,所以+4,就等于指

                                                                             针自增1.此时edx的数据就是a[1]的偏移地址了。
    002113DF  mov         dword ptr [ebp-28h],edx  //把edx的值传入内存
dword ptr [ebp-28h]中,及p

                                                                             指针现在指向a[1]的地址。

 

 

    对于

   

                p = a;
    002113FD  lea         eax,[ebp-1Ch] 
    00211400  mov         dword ptr [ebp-28h],eax 
                b = *++p;
    00211403  mov         eax,dword ptr [ebp-28h] 
    00211406  add         eax,4 
    00211409  mov         dword ptr [ebp-28h],eax 
    0021140C  mov         ecx,dword ptr [ebp-28h] 
    0021140F  mov         edx,dword ptr [ecx] 
    00211411  mov         dword ptr [ebp-34h],edx

 

    基本差不多的汇编语句,不同的是先把p指针自增,然后取出p指针指向的值。再把该值赋给b.

 

      以上仅对前++和后++的操作给出汇编一些运算逻辑。。希望给感兴趣的人能提供点帮助,如果有表

 

达不清楚,或者不好的地方。。欢迎大家指出。。交流才会让大家提高更快。。。。

 

 

 

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值