VC 中 C/C++ 增减量运算符解析
——ILLI
VC中前后缀增减量运算法则:
(1)优先级:前缀>算术运算 >后缀;
(2)结合性:前缀左结合,后缀右结合。
C/C++的增减量运算符分为自增(++)和自减(--)两种,同时又有前缀和后缀之别,在C/C++程序中也较为常见。单一的增减量运算符很好理解,但若一个表达式中出现多次增减量运算,则很容易混淆不清。因此,搞清楚增减量运算符的优先级和结合性是非常有必要的。原理能够弄懂,那么一切相关的问题便可迎刃而解了。不过,一个良好风格的代码是不应该在一个表达式中多次出现增减量运算的。
为了能在这些++、--中游刃有余,我便在win7 32位系统上用VS2008进行了一番测试。然后,得出了下面的三条结论:(该测试是针对算术运算中的加减法而进行的):
(1)前缀比后缀的优先级高;
(2)前后缀混合时,算术运算处于中间;
(3)同为前缀时,从左往右算;同为后缀时,从右往左算;
于是,可以得到以下推论:
(1)前缀>算术运算 >后缀:即前缀增减量的优先级大于算术运算,算术运算的优先级大于后缀;
(2)前缀的结合性为左结合,后缀的结合性为右结合:即当一个表达式中有多个前缀增减量运算时,是从左往右依次进行运算的;而当一个表达式中有多个后缀增减量运算时,是从右往左依次进行的。
有了以上的结果,便可以很容易地对各种增减量运算进行正确的运算了。虽然又是结论又是推论的,但其实只需要记住推论中的两点:(1)前缀> 算术运算 > 后缀;(2)前缀左结合,后缀右结合。第一点是说优先级的,第二点是说结合性的。
不过、但是、然而……很不幸的是,在C/C++的运算符优先级表中,后缀增减量的优先级比前缀增减量的优先级要高;同时后缀增减量是左结合的,而前缀增减量是右结合的;并且它们的优先级都高于算术运算。这完全和测试的结果相反,至于为什么那就得问问VS开发者了。
标准和现实总是有差距的,各种编译器所遵循的也不大相同,具体的最好就是自己亲自去测试测试。我也只是在VS2008上进行了测试,以供诸君共勉,若有错漏,还望多多指教。
(附注:另外我对关系、逻辑和位运算的每个运算符进行了基于前后缀增减的各种组合的抽样测试(这个当然也很少用到,不用理它,看看就行),得到的结果是:
逻辑非、按位取反 >前缀 >算术运算 >位运算 >后缀 >关系运算 >逻辑运算
这些大都和标准的C/C++运算符优先级表中一致,只是在VS的前后缀增量运算中后缀增减量运算后跨到了算术运算和位运算后面。)
附录:
1.一个变量的增减量测试
int a = i++ + --i;
// 前后缀混合运算,根据推论1,知道先算前--i,然后是算术运算+,最后是后缀i++
i -= 1;
a = i + i;
i += 1;
2. 两个变量的增减量测试
s = a++ + b--;
//因为都是后缀,所以根据推论1,要先进行算术+运算;
// 根据推论2,后缀的结合性是右结合,所以先b--,在a++
002D3573 mov eax,dword ptr [a]//把a移到eax寄存器
002D3576 add eax,dword ptr [b]//再和b相加,结果依然保存在eax中
002D3579 mov dword ptr [s],eax
002D357C mov ecx,dword ptr [b]// 把b移到ecx寄存器,然后减1,保存结果到ecx
002D357F sub ecx,1
002D3582 mov dword ptr [b],ecx//把它移到b中去,就让b的值“自减”1了。
002D3585 mov edx,dword ptr [a]// a自增1的原理同b。
002D3588 add edx,1
002D358B mov dword ptr [a],edx