x = x++;
请问上述两行代码执行之后,x的值是什么?
有的同事说1,有的同事说0,究竟是什么呢,试试就知道。
试了三个编辑器,Inter,gcc和vc自带的cl。
Inter和gcc得出的结果都是0,vc得出的结果是1。
究竟哪个对呢?
让我们再看看那两行代码,第一行不用多说,把一个变量赋值为0,第二行是由两部分组成的,一部分是一个赋值语句,也就是 operator =(),一部分是后置++操作符,也就是operator ++()。
后置++的行为在c++中的标准中有明确的定义:首先,取出当前操作数(本例为x,下面均已x代替)的值,放到一个临时变量中,例如y,然后再把当前x的值加上1,然后返回那个临时变量的值,也就是y的值,这三个操作是一个原子操作,中间不能插入其他代码。所以,operator ++返回的是x未加上1之前的值。
这样答案就很明显了,按照c++标准,先取出x的值(例子中x的初值为0)放入y,x加上1,这时x的值是1,把operator++返回的y的值(也就是0)赋值给x,这时,x的值就从1变成0了,由此可见,Inter和gcc在这个操作符的实现比VC更符合c++的标准。
operator- -() 也是得到相似的结果。
下面列出VC和gcc所编译出来的这两行代码的汇编代码,可以更清楚的看出这两个编译器对后置操作符的实现。
先列出VC的,我试了vc.net 2003和最新的vc.net 2008,得到的结果是一样的。
int x = 0;
0041138E mov dword ptr [x],0 ; 给x赋初值为0
x = x++;
00411395 mov eax,dword ptr [x] ; 取出x的值,放入eax中
00411398 mov dword ptr [x],eax ; 取出eax的值,放入x中,这两句对应的c代码是x = x,可以看出,先执行了赋值操作。
0041139B mov ecx,dword ptr [x] ; 取出x的值,放入ecx中
0041139E add ecx,1 ; 把ecx中的值加1
004113A1 mov dword ptr [x],ecx ; 把ecx中的值赋值给x,以上三句执行的是c代码更像是++x。
以上就是VC编译出来的代码,按这样的代码执行,得到的结果当然是1,从上面的汇编代码可以看出,在VC的实现中,如果operation ++与 operator = 一起出现时,先执行的是operator =。
接下来,我们看看gcc编译出的汇编代码。
movl $0, -4(%ebp) ; 把x初始化为0
movl -4(%ebp), %edx ; 把x的值放入到edx中,edx的值就会作为opeator ++的返回值
leal -4(%ebp), %eax ; 取出x的地址,放入eax中
incl (%eax) ; 把eax中的值加1,实际上就是对x的值加1,执行之后,x=1
movl %edx, -4(%ebp) ; 把edx的值赋值给x,执行之后,x=0
由此可见,gcc的实现完全符合c++标准中的实现,把x的值放入临时变量,对x加1,返回临时变量的值,三步操作一口气完成,中间不夹其他操作。
总结:在operator ++和 operator = 一起出现的时候,VC的实现先执行 operator =,再执行 operator ++,不符合c++标准。而gcc的实现就是符合c++标准的。当然,在实际开发时不应写这种晦涩难懂的代码,一是你不能保证这种代码在各种平台上的实现是一致的,二是维护起来也麻烦。
最后摘抄一段c++ iso文档的后置++的描述。
The value obtained by applying a postfix ++ is the value that the operand had before applying the operator.[Note:the value obtained is a copy of the original value ] The operand shall be a modifiable lvalue. The type of the operand shall be an arithmetic type or a pointer to a complete object type. After the result is noted, the value of the object is modified by adding 1 to it, unless the object is of type bool, in which case it is set to true.