分类: C/C++
2014-04-23 10:31:29
自增运算符是C++的一个单目运算符,也就是说只能有一个作用对象。大家都知道++有左++和右++两种。其中的区别大家可能也了解一些。不过这两者之间究竟有什么本质区别呢?
其实,++不是一个“素运算”。或者说它是几个运算的合成。并且这种合成不是唯一的,随语法和编译环境影响。我们先看一下受编译环境影响最小的两种情况x=i++;和y=++j;
要了解一个东西,追源溯本是很管用的方法。大家都知道C++是高级语言,高级语言在编译和连接之后成为机器语言代码,所以我们可以直接查看机器代码来了解C++中的左++和右++究竟让机器在背后做了什么。
======================我是分割线喵======================
把x=i++反汇编(就是把编译连接后的结果反向操作写成汇编语言)。
我们可以看到x=i++变成了五个汇编指令(不用担心看不懂喵,会解释喵):
mov eax,dword ptr[i]
mov dword ptr[x],eax
mov ecx,dword ptr[i]
add ecx,1
mov dword ptr [i],ecx
不要头晕喵,我们不用弄清每个指令到底是什么,只需要大致看一下它们的意思:
mov eax,dword ptr[i] ;将变量i的值储存进寄存器eax(寄存器在这里就当做是储存器吧,寄存器eax就是叫eax的储存器)
mov dword ptr[x],eax ;将寄存器eax的值存进变量x,因为eax存了i的值,所以现在x==i
mov ecx,dword ptr[i] ;将变量i的值放进另一个寄存器ecx
add ecx,1 ;字面意思,ecx加上一,现在ecx里面存的是i+1哦。不要头晕
mov dword ptr [i],ecx 把ecx的值放回变量i。也就是i变成i+1了。
综上,x=i++使得x变成了i,i变成了i+1。
======================我是分割线喵======================
那么现在来看下y=++j会有什么不同喵。
喵。
mov eax,dword ptr[j]
add eax,1
mov dword ptr[j],eax
mov ecx,dword ptr[j]
mov dword ptr [y],ecx
看起来和上面很类似的。经过上面的解释相信大家应该能自己看懂了,我还是简单解释下吧
mov eax,dword ptr[j] ;将变量j的值储存进寄存器eax
add eax,1 ;字面意思。。。。。。eax加上1,现在eax里面存的是j+1
mov dword ptr[j],eax ;将寄存器eax的值存进变量j,因为eax存了j+1的值,所以"现在的j"=="原来的j"+1
mov ecx,dword ptr[j] ;将变量j的值放进另一个寄存器ecx,现在j和ecx里面都存着j+1了
mov dword ptr [y],ecx ;把ecx里面的j+1存进变量y
综上,y=++j使得j变成j+1,y变成j+1.
======================我是分割线喵======================
现在,我们来形式的看一下i++和++j的汇编代码的区别。看看上面的两个代码,其实只是中间三行换了下顺序。但是左++和右++的区别是不是真的这么简单呢。答案是否定的。高级语言里面可以构造出很多复杂的语句,比如
x=i+++++i+++i;
y+=y+++++y,(++y||y++)?++y:y++;
等这种变态语句。
这种语句在不同的编译环境会有不同的编译结果。也就是说用不同的编译器编译出不同的结果。其中
add eax,1
究竟会出现在哪里,是不确定的。所以尽量避免是用除x=i++这种简单语句之外的含++运算符的语句。
--的原理是完全一样的,在此就不讨论了