困惑新手的++(--)运算符,很多老师都会这么说,++在前就先加后运算 ,++在后就先运算,再自增1,
国内大学C接触的也多半是谭XX教授编写的(反正当时我们是这样的),在书里经常搞来搞去,搞一堆运算式放在一起,非得你记起来他们的优先级,清楚他们的与语法才能知道结果。对于我这种不太死记硬背的人来说,我觉得还是写一些明确的表达式会让看的人心里比较舒畅一点,比如该加括号就加括号,该拆分就拆分。
废话不多说,看下面代码,代码很简单,有点基础一看就知道结果,不过这不重要,想要弄清楚到底是怎么运算的,很简单,反汇编即可:
代码及反汇编代码:
#include <stdio.h>
int main()
{
int i = 1;
0132138E mov dword ptr [i],1
int j = 1;
01321395 mov dword ptr [j],1
i++;
0132139C mov eax,dword ptr [i]
0132139F add eax,1
013213A2 mov dword ptr [i],eax // i = i + 1
++i;
013213A5 mov eax,dword ptr [i]
013213A8 add eax,1
013213AB mov dword ptr [i],eax // i = i + 1, 可见,单独的i++, ++i是一样的。
j = j + i++;
013213AE mov eax,dword ptr [j]
013213B1 add eax,dword ptr [i]
013213B4 mov dword ptr [j],eax // j = i + j;
013213B7 mov ecx,dword ptr [i]
013213BA add ecx,1
013213BD mov dword ptr [i],ecx // 然后 i = i + 1
j = j + ++i;
013213C0 mov eax,dword ptr [i]
013213C3 add eax,1
013213C6 mov dword ptr [i],eax // i = i + 1
013213C9 mov ecx,dword ptr [j]
013213CC add ecx,dword ptr [i]
013213CF mov dword ptr [j],ecx // 然后 j = j + i
j = j + i++ + i++;
013213D2 mov eax,dword ptr [j]
013213D5 add eax,dword ptr [i]
013213D8 add eax,dword ptr [i]
013213DB mov dword ptr [j],eax // j = j + i + i
013213DE mov ecx,dword ptr [i]
013213E1 add ecx,1
013213E4 mov dword ptr [i],ecx // 然后 i = i + 1
013213E7 mov edx,dword ptr [i]
013213EA add edx,1
013213ED mov dword ptr [i],edx // 再次 i = i + 1
j = j + ++i + ++i;
013213F0 mov eax,dword ptr [i]
013213F3 add eax,1
013213F6 mov dword ptr [i],eax // i = i + 1
013213F9 mov ecx,dword ptr [i]
013213FC add ecx,1
013213FF mov dword ptr [i],ecx // 再次 i = i + 1
01321402 mov edx,dword ptr [j]
01321405 add edx,dword ptr [i]
01321408 add edx,dword ptr [i]
0132140B mov dword ptr [j],edx // 然后 j = j + i + i
return 0;
0132140E xor eax,eax
}
根据以上的代码注释,显然,单独的 i++ , ++i 是一样的,当在一个复杂的表达式里,则表现不太一样。而且一个表达式里多次出现i++或者++i的时候,也可以根据上面的规律拆分。
虽然我们可以根据运算符的优先级来推测结果,但是能一目了然的代码为什么不写呢?所以建议大家,i++ 或者++i应该单独写,不要写在复杂表达式里。让人有想砍你的冲动。
例如
j = j + i++;
写成
i++;
j = j + i;
或者
i++;
j += i;
以上发汇编结果是在VS中测试的,C/C++在这个问题上,是由编译器决定的,这段汇编是经过编译器优化的结果,然而像在java 或者C#中,++问题是用语言来规定规则的,所以在java/C#中,涉及++的运算结果是可以确定的,但是C/C++的编译器有很多种,不保证每一种编译器优化的结果都是一致。
隔了一年,我再回来看到这个自己写的东西,有必要更新一下。因为上面这种情况是对于一个整形变量的运算,所以说法还算成立,但是最近自己研究STL源代码的时候,发现上面的说法用在迭代器中并不适用。
来看一看SGI STL中list的迭代器的++重载:
//前置++
_Self& operator++() {
this->_M_incr();
return *this;
}
//后置++,括号中加了一个int,表示这是后置++,并没有其他的意思
_Self operator++(int) {
_Self __tmp = *this;
this->_M_incr();
return __tmp;
}
明显可以看到。后置++中需要分配一个临时变量来保存当前的这个迭代器所包装的数据。然后像前置++一样,调用了相同的递增函数。。然后返回保存下来的数据的迭代。
那么当我们对迭代器单独使用++的时候,放在前和放在后,是不一样的。为了效率更高。当然选择前置++ 。
如下:
//第一种
list<int>::iterator it = xx.begin();
for (; it != xx.end(); ++it)
{
}
//第二种
list<int>::iterator it = xx.begin();
for (; it != xx.end(); it++)
{
}
显然第一种效率会高一些。如果数据量很大。循环次数较多的时候。第一种就会比第二种明显快一些。