C++中关于操作符先(++)后(++)问题的讨论

来源:互联网 发布:js 二维数组 push 编辑:程序博客网 时间:2024/04/28 18:05
#include<stdio.h>
void main()
{
    int x,a=4;
    x=a+(a++);
    printf("%d/n",x);
}
#include<stdio.h>
void main()
{
    int a=4;
    a=a+(a++);
    printf("%d/n",a);
}
 
请问为什么会输出不一样的结果?
答:
为了说明问题我们来做一个实验
首先把
x=a+(a++);变成x=a+a++;
的括号去掉
同样把
a=a+(a++);变成a=a+a++
括号也去掉
通过这种改变,我们得出的结果看是否与括号有关。
实验得出的结果是:实验结果是无关。
并且根据资料我们知道,括号的优先级高于双目(+)优先级,也高于单目(++)优先级,而单目(++)优先级高于双目优先级
那么括号的目的是:优先级的改变:无论哪一种语言,都有一个特殊的运算符,那就是括号,这个运算符的作用可以说有2个,一个是改变其他运算符的优先级,再一个就是使得表达式更容易理解。我们可以在一些有歧义的表达式中适当的位置加上括号,以消除歧义。
而楼上的分析
1 a=4, +的优先级高于a++ ,所以x=4+4=8
2 a=4 a=4+4=8 然后a++   , a=9
不对的,因为有括号的错字所以肯定优先计算a++
所以问题的根本原因还是出在a++上
首先看x=a+(a++);
根据编译器计算顺序,首先把a(4)的值放入x的
重点分析
在此我们不妨分析下先++和后++区别。
为了说明问题在代码中定义了x1a1
74:       int x,a=4;
004012E8   mov         dword ptr [ebp-8],4// x的地址是ptr [ebp-8],a的地址ptr [ebp-8]赋值a=4;
75:       x=a+(a++);
004012EF   mov         eax,dword ptr [ebp-8]//首先把小a=4的值放入eax
004012F2   add         eax,dword ptr [ebp-8]// eax的值与a(4)的值相加()
004012F5   mov         dword ptr [ebp-4],eax//把eax的值放入x内
004012F8   mov         ecx,dword ptr [ebp-8]// 把a的值放入ecx
004012FB   add         ecx,1//ecx的值加1(等于5)
004012FE   mov         dword ptr [ebp-8],ecx//把ecx的值放入a内
76:        int x1,a1=4;
00401301   mov         dword ptr [ebp-10h],4//a1的地址ptr [ebp-10h]赋值a1=4;
 
77:        a1=a1+(a1++);
00401308   mov         edx,dword ptr [ebp-10h]// 把al的值放入edx(4)
0040130B   add         edx,dword ptr [ebp-10h]// edx与地址a1相加(值是8)
0040130E   mov         dword ptr [ebp-10h],edx// 把edx的值放入dword ptr [ebp-10h]
00401311   mov         eax,dword ptr [ebp-10h] // 把dword ptr [ebp-10h]的值放入eax(8)
00401314   add         eax,1// 加1操作(9)
00401317   mov         dword ptr [ebp-10h],eax// 注意了,此处把eax赋值到a1了。
 
通过上面的分析我们可以清楚地知道x=a+(a++);和a1=a1+(a1++);过程,得出不同结果的原因是a++的机制问题,a++的原理是
Int iTemp;
iTemp = a+1;
a = iTemp;
所以因为这个原因存在导致a,和x的值不一样。
那么我们有什么办法可以保证x,a的行为一致性那?我们采用++a的方法
看下面的汇编代码,
74:       int x,a=4;
004012E8   mov         dword ptr [ebp-8],4
75:       x=a+(++a);
004012EF   mov         eax,dword ptr [ebp-8]
004012F2   add         eax,1
004012F5   mov         dword ptr [ebp-8],eax
004012F8  mov         ecx,dword ptr [ebp-8]
004012FB   add         ecx,dword ptr [ebp-8]
004012FE   mov         dword ptr [ebp-4],ecx
76:        int x1,a1=4;
00401301   mov         dword ptr [ebp-10h],4
77:        a1=a1+(++a1);
00401308   mov         edx,dword ptr [ebp-10h]
0040130B   add         edx,1
0040130E   mov         dword ptr [ebp-10h],edx
00401311   mov         eax,dword ptr [ebp-10h]
00401314   add         eax,dword ptr [ebp-10h]
00401317   mov         dword ptr [ebp-10h],eax
大家都是聪明人,以上的部分不在分析了,
但是结果我们知道x,a的值都为10。那么我们看++a的机制
a = a+1;
对不a++
Int itemp;
Itemp = a+1;
a = itemp;
看见了,我们平时没有注意到先++和后++原来还存在效率问题,那么什么效率问题那?
我们对比上面的代码,可嫩并没有发现什么空间与时间上的效率问题,但是如果此处的a是一个对象,而不是内置类型那?
比如:Class A;在a中重载了先++和后++
那么我们使用a++,和++a的时候就要考虑了。
如果用a++
A atemp;//构造函数
atemp = a+1;//赋值操作符
a = atemp;//又一个赋值操作符
即使使用拷贝构造函数,那么我们也必须为要构建一个新的临时对象,来定义a,在执行a+1
操作,在执行一个赋值操作,浪费了时间和空间!
再看
++a
a= a +1;// 只是使用必须的+1操作,和赋值操作。其实编译器可以优化,就可以连赋值操作都不用。因为类的加(+)操作返回对象就是本身对象的地址引用。
 
所以,如果你真的还没有理解上面的意思,后者你认为先++后++对你没有什么影响,那么放心的采用先++吧。培养自己的良好习惯。
For(int i = 0; i < 3; ++i)// 从此以后开始这样写吧
原创粉丝点击