`
jishublog
  • 浏览: 870848 次
文章分类
社区版块
存档分类
最新评论

x=x++带来的困惑。。。

 
阅读更多

今天微软实习生笔试,有一个题目,本来我认为没有什么值得考虑的,结果出来同学一讨论,出现一边倒的结果,当然我不是那一边的,我就想当郁闷呀。

问题主要是:

int x = 10;
x = x++;
cout<<x<<endl;
我想也没想,这结果当然是10了,可以同学回来都说是11,然后再机器上一测试,结果果然是11,我感觉整个人生观被颠覆了。

我清楚的记得后置形式自增/自减,的计算顺序是:先保存操作数原来的值,然后对操作数进行自增/自减操作,然后返回之前保存的操作数的值即未进行自增/自减操作的值。在C++ Primer第四版 P140也是这么说的:


Fig 1

由C++ Primer说法可知,之所以必须先保存操作数原来的值,是因为在返回自增表达式结果之前,会对操作数进行自增运算。

但现在的结果变成了把自增操作放到了复制操作的后面,下面是反汇编的结果:

    int x = 10;
0041191D  mov         dword ptr [ebp-14h],0Ah 
    x = x++;
00411924  mov         eax,dword ptr [ebp-14h] 
00411927  mov         dword ptr [ebp-14h],eax 
0041192A  mov         ecx,dword ptr [ebp-14h] 
0041192D  add         ecx,1 
00411930  mov         dword ptr [ebp-14h],ecx 

在Fig 1中有这么一句话:对于int型对象和指针,编译器可优化点这项额外工作,但是对于更多的复杂迭代器 类型,这种额外工作可能会花费更大的代价

所以我做了下面的测试:

    vector<int> y;
    for (int i = 0; i < 10; ++i)
    {
        y.push_back(i);
    }

    vector<int>::iterator itr = y.begin();
    while(itr != y.end())
    {
        itr = itr++;
        cout<<*itr<<endl;
    }
如果说和上面的x一样的话,迭代器解引用会输出y中的所有元素(当然这里代码有点问题,就是itr会指向end,会出错,但不影响测试)。但是结果是死循环,始终输出0,这也就表明:itr = itr++的计算顺序是先保存itr的值,然后对itr进行++操作,然后把事先保存的itr的值赋给itr。

下面是反汇编结果的代码

    itr=itr++;
00411A16  push        0    
00411A18  lea         eax,[ebp-13Ch] 
00411A1E  push        eax  
00411A1F  lea         ecx,[ebp-5Ch] 
00411A22  call        std::_Vector_iterator<int,std::allocator<int> >::operator++ (41100Ah) 
00411A27  mov         dword ptr [ebp-164h],eax 
00411A2D  mov         ecx,dword ptr [ebp-164h] 
00411A33  mov         dword ptr [ebp-168h],ecx 
00411A39  mov         byte ptr [ebp-4],3 
00411A3D  mov         edx,dword ptr [ebp-168h] 
00411A43  push        edx  
00411A44  lea         ecx,[ebp-5Ch] 
00411A47  call        std::_Vector_iterator<int,std::allocator<int> >::operator= (41100Fh) 
00411A4C  mov         byte ptr [ebp-4],1 
00411A50  lea         ecx,[ebp-13Ch] 
00411A56  call        std::_Vector_iterator<int,std::allocator<int> >::~_Vector_iterator<int,std::allocator<int> > (411064h) 
由反汇编的结果可以知道,是先保存itr的值,然后对itr进行++操作,然后把事先保存的itr的值赋给itr。

所以可知对于int型对象和指针,编译器进行了优化,直接把x的值赋给了表达式左边的值,然后对x进行自增,而对于迭代器类型,并没有进行优化;

所以说:x从C标准定义的结果应该是10,而不是11。

Apr 6, 2013 @lab

博客内容修改:

C/C++标准除了对操作符:&&,||, ?:,,(逗号操作符)这四个操作符定义了求值顺序,对于其他的操作符都未定义求值顺序,所以上面所讨论的问题,只是编译器的实现问题,标准从未定义过,具体可参考C++ Primer P149 ,和http://bbs.csdn.net/topics/370153775,谢谢1楼和2楼的提醒

修改时间:Apr 7, 2013

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics