天天看点

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

#include<stdio.h>

void main()

{

    int x,a=4;

    x=a+(a++);

    printf("%d/n",x);

}

    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的

重点分析

在此我们不妨分析下先++和后++区别。

为了说明问题在代码中定义了x1,a1

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的方法

看下面的汇编代码,

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

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++

看见了,我们平时没有注意到先++和后++原来还存在效率问题,那么什么效率问题那?

我们对比上面的代码,可嫩并没有发现什么空间与时间上的效率问题,但是如果此处的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)// 从此以后开始这样写吧

继续阅读