++a和a++的相关问题

int a=1;
int b,c;
b=(a++)+(a++)+(a++);
//计算结果:b=3,a=4

int a=1;
c=(++a)+(++a)+(++a);
//计算结果:c=10,a=4

为什么c=10呢?

结果与编译器有关,gcc得出的结果也是10。

下面是一个测试的源代码:
int main(int argc, char argv[])
{
  int a = 1;
  int b,c;
 
  b = (a++)+(a++)+(a++);
  printf("b = %d, a = %d./n", b, a); // b = 3, a = 4.

  a = 1;
  c = (++a) + (++a) + (++a);

  printf("c = %d, a = %d./n", c, a); // b = 10, a = 4

  return 1;
}

下面是在Linux环境下通过反汇编得到的源程序和汇编代码混合的文件,这里只给出main函数。

int main(int argc, char argv[])
{
 8048328:    55                          push   %ebp
 8048329:    89 e5                    mov    %esp,%ebp
 804832b:    83 ec 18               sub    $0x18,%esp
 804832e:    83 e4 f0                and    $0xfffffff0,%esp
 8048331:    b8 00 00 00 00   mov    $0x0,%eax
 8048336:    29 c4                    sub    %eax,%esp
  int a = 1;
 8048338:    c7 45 fc 01 00 00 00     movl   $0x1,0xfffffffc(%ebp) // 0xfffffffc(%ebp) 存放的是临时变量a
  int b,c;
 
  b = (a++)+(a++)+(a++);
 804833f:    8b 55 fc                 mov    0xfffffffc(%ebp),%edx // a->edx
 8048342:    8b 45 fc                mov    0xfffffffc(%ebp),%eax // a->eax
 8048345:    01 c2                    add    %eax,%edx             // a + a -> edx, eax = a
 8048347:    8b 45 fc                mov    0xfffffffc(%ebp),%eax
 804834a:    8d 04 10              lea    (%eax,%edx,1),%eax    // ?
 804834d:    89 45 f8               mov    %eax,0xfffffff8(%ebp) // b = (a++)+(a++)+(a++).这里结果存放在临时变量b

 8048350:    8d 45 fc               lea    0xfffffffc(%ebp),%eax // eax 指向临时变量a,这里执行的是三个a++.
 8048353:    ff 00                      incl   (%eax)
 8048355:    8d 45 fc               lea    0xfffffffc(%ebp),%eax
 8048358:    ff 00                      incl   (%eax)
 804835a:    8d 45 fc               lea    0xfffffffc(%ebp),%eax
 804835d:    ff 00                      incl   (%eax)
  printf("b = %d, a = %d./n", b, a);
 804835f:    83 ec 04               sub    $0x4,%esp
 8048362:    ff 75 fc                 pushl  0xfffffffc(%ebp)
 8048365:    ff 75 f8                 pushl  0xfffffff8(%ebp)
 8048368:    68 64 84 04 08  push   $0x8048464
 804836d:    e8 f6 fe ff ff          call   8048268 <_init+0x38>
 8048372:    83 c4 10              add    $0x10,%esp

  a = 1;
 8048375:    c7 45 fc 01 00 00 00     movl   $0x1,0xfffffffc(%ebp)  // 临时变量    a被赋予初值1
  c = (++a) + (++a) + (++a);
 804837c:    8d 45 fc               lea    0xfffffffc(%ebp),%eax  // eax指向临时变量a
 804837f:    ff 00                       incl   (%eax)           //  ++a

 8048381:    8d 45 fc               lea    0xfffffffc(%ebp),%eax // eax指向临时变量a
 8048384:    ff 00                      incl   (%eax)              //  ++a   

 8048386:    8b 45 fc               mov    0xfffffffc(%ebp),%eax // 此时a应该等于3
 8048389:    8b 55 fc               mov    0xfffffffc(%ebp),%edx // edx指向临时变量a
 804838c:    01 c2                    add    %eax,%edx             // edx = eax + edx

 804838e:    8d 45 fc               lea    0xfffffffc(%ebp),%eax // ++a
 8048391:    ff 00                     incl   (%eax)

 8048393:    89 d0                  mov    %edx,%eax         // edx->eax
 8048395:    03 45 fc              add    0xfffffffc(%ebp),%eax

 8048398:    89 45 f4              mov    %eax,0xfffffff4(%ebp)  // 结果存放到c中去

  printf("c = %d, a = %d./n", c, a);
 804839b:    83 ec 04             sub    $0x4,%esp
 804839e:    ff 75 fc                 pushl  0xfffffffc(%ebp)
 80483a1:    ff 75 f4                 pushl  0xfffffff4(%ebp)
 80483a4:    68 75 84 04 08  push   $0x8048475
 80483a9:    e8 ba fe ff ff        call   8048268 <_init+0x38>
 80483ae:    83 c4 10             add    $0x10,%esp

  return 1;
 80483b1:    b8 01 00 00 00  mov    $0x1,%eax
}
 80483b6:    c9                       leave 
 80483b7:    c3                       ret   

可以看出:
1。第1个式子b = (a++)+(a++)+(a++);的编译器的编译结果是:
先将3个a的值相加,结果存放在临时变量b中。然后,三次增加临时变量a的值。

  int a = 1;
 8048338:    c7 45 fc 01 00 00 00     movl   $0x1,0xfffffffc(%ebp) // 0xfffffffc(%ebp) 存放的是临时变量a
  int b,c;
 
  b = (a++)+(a++)+(a++);
 804833f:    8b 55 fc               mov    0xfffffffc(%ebp),%edx // a->edx
 8048342:    8b 45 fc              mov    0xfffffffc(%ebp),%eax // a->eax
 8048345:    01 c2                  add    %eax,%edx             // a + a -> edx, eax = a
 8048347:    8b 45 fc              mov    0xfffffffc(%ebp),%eax
 804834a:    8d 04 10            lea    (%eax,%edx,1),%eax    // ?
 804834d:    89 45 f8             mov    %eax,0xfffffff8(%ebp) // b = (a++)+(a++)+(a++).这里结果存放在临时变量b

 8048350:    8d 45 fc             lea    0xfffffffc(%ebp),%eax // eax 指向临时变量a,这里执行的是三个a++.
 8048353:    ff 00                    incl   (%eax)
 8048355:    8d 45 fc             lea    0xfffffffc(%ebp),%eax
 8048358:    ff 00                    incl   (%eax)
 804835a:    8d 45 fc             lea    0xfffffffc(%ebp),%eax
 804835d:    ff 00                    incl   (%eax)

2。第2个式子,其做法就不同。
实际做法是:
-。首先执行第一个++a,方法是gcc把a的地址放进寄存器%eax,然后incl(%eax);
然后解析表达式,遇到后面是+号,加法是需要左值和右值的,所以还要计算右值;
-。然后执行第二个++a,方法也是gcc把a的地址放进寄存器%eax,然后incl(%eax);
此时a的值是3。
-。这个时候左值和右值都有了,可以运行加法了,但是这个时候的a变成了3;
这里的加法是a的值分别取到edx和eax中,然后相加,
所以加出来的值就是3+3=6;这个临时值被放进了一个寄存器(这里是%edx);
上面的例子中又+(++a);这个时候再把a的地址放进寄存器%eax,然后incl(%eax)
-。最后把%edx和a的值相加就可以了;
这里的关键是第1个++a中,表达式(++a)的值没有使用临时变量来缓存,到执行加法的时候是直接再从临时变量a取的值。

  a = 1;
 8048375:    c7 45 fc 01 00 00 00     movl   $0x1,0xfffffffc(%ebp)  // 临时变量    a被赋予初值1
  c = (++a) + (++a) + (++a);
 804837c:    8d 45 fc             lea    0xfffffffc(%ebp),%eax  // eax指向临时变量a
 804837f:    ff 00                     incl   (%eax)           //  ++a

 8048381:    8d 45 fc             lea    0xfffffffc(%ebp),%eax // eax指向临时变量a
 8048384:    ff 00                    incl   (%eax)              //  ++a   

 8048386:    8b 45 fc             mov    0xfffffffc(%ebp),%eax // 此时a应该等于3
 8048389:    8b 55 fc             mov    0xfffffffc(%ebp),%edx // edx指向临时变量a
 804838c:    01 c2                  add    %eax,%edx             // edx = eax + edx

 804838e:    8d 45 fc             lea    0xfffffffc(%ebp),%eax // ++a
 8048391:    ff 00                    incl   (%eax)

 8048393:    89 d0                 mov    %edx,%eax         // edx->eax
 8048395:    03 45 fc             add    0xfffffffc(%ebp),%eax

 8048398:    89 45 f4             mov    %eax,0xfffffff4(%ebp)  // 结果存放到c中去
结论:
这里只是在VC和Linux环境下的gcc中做过验证,其他环境尚不清楚。
结论就是如果需要明确的结果,建议去掉这种可能产生歧义的表达式。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值