深度讨论C\C++中++i与i++的区别 - sbw Blog

深度讨论C\C++中++i与i++的区别

来源: 石博文博客 | 浏览: 6022 | 评论: 0 发表时间: 2013-08-02

对于程序设计中经常用到的i++,++i语句,一般的教科书上都只用一段很简单的'先前++,后计算,再后++'来说明,但其实在程序运行中,并不是这样,关于i++与++i的执行效率问题,还有左值,右值的概念,本文将深度讨论i++与++i到底有什么区别.



先来看这样一道题目:(某企业面试题)


设有int a=1;那么下面几条语句哪些有错,哪些正确?

这道题目并不是考++a与a++的计算先后,而是考左值与右值的概念,那么我们用下面这个例子讲一下什么是左值,右值.还有i++与++i到底有什么区别.


我们有上面这样的C++代码,一个用了++a,另一个用到a++,然后使用g++ -S 将这个程序编译为汇编文件.得到下面的代码:


汇编代码

为了方便阅读,我把-4(%ebp)替换为a,-8(%ebp)替换为b.在汇编代码中,19~23行完成了C++代码的第6行,33~36行完成了C++代码的第8行,先不说别的,单从代码量上,我们就能得到第一个结论:++i比i++效率高.


然后再来看核心的a++与++a语句完成的位置,在19行,将a复制到eax中,然后使用leal给rax加1,放入到edx中.其实这块语句写成这样会比较好理解:


但是语句又增加一条.leal 1(%rax),%edx 完成的就是上面代码的2~3行,即把eax中的数据取出,加1后送到edx中.下面一条的movl %edx,a 就已经把a+1放入到a变量的内存地址中去了.即在第4行就完成了a++,之后使用的没有加1的a变量是保存在eax中的值.


再来看C++代码的第8行汇编结果,直接就对a变量加1,然后使用a变量计算,++a的完成位置就在33行.


由此我们可得出一个结论,++i与i++并不是教科书上写的那样,++i在计算之前加,i++在计算之后加,在表达式真正计算之前,就已经完成了++i和i++.他们的区别在于,使用i++时,程序会把没有做加法前的变量拷贝一份,在之后的表达式求值中使用这个副本来做计算,这就引出了'左值'和'右值'的概念.


用一句话来讲左值与右值,左值代表了一个变量,拥有自己内存地址的空间,而右值是一个常数,它并没有内存空间,我们只能给内存中写入数据,而不能给一个常量写入数据.


在++i中,由于直接操作对象就是i这个变量,所以说,++i返回的是一个左值.


而在i++中,在计算之前i已经加了1,我们操作的是它没有加1时的一个副本(或者说'快照'),它只是一个存在于寄存器中的一个临时常数,并没有自己的内存地址,因此不能对它赋值.所以说,i++返回一个右值.


所以,对于开始那个题目,显然C,D错误,因为我们不能给一个常量(右值)赋值.


不能给一个常量赋值
最后的总结

1. ++i比i++执行效率高,如果只是想把变量加1的话,尽量使用++i.

2. ++i与i++都是在计算表达式之前就已经加1了的.

3. ++i返回左值,可写入,i++返回右值,不可写入.



C++

没有人评论过此文,还不快抢个沙发
  • 昵称: *
  • 邮箱:
  • 网址:
  • 记住我的信息
  • Color
  • Red
  • Blue
  • Code
  • bash
  • cpp
  • css
  • java
  • js
  • perl
  • php
  • python
  • ruby
  • sql
  • xml