今天微软实习生笔试,有一个题目,本来我认为没有什么值得考虑的,结果出来同学一讨论,出现一边倒的结果,当然我不是那一边的,我就想当郁闷呀。
问题主要是:
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
分享到:
相关推荐
该程序并演示了如何设置 ADXL345 加速度计以及访问 X、Y 和 Z 数据。 访问滚动和俯仰输出。 ##启用硬件中断 ADXL345 有两个中断引脚,在这种情况下,只使用一个, INT-1作为中断源通知系统。 它与GPIO2_1(HardWware...
C语言的自增++,自减--运算符对于初学者来说一直都是个难题,甚至很多老手也会产生困惑,最近我在网上看到一个问题: #include void main() /*主函数*/ { int a,b,c,d; a=5; b=5; c=...
lambda的语法时常会使人感到困惑,lambda是什么,为什么要使用lambda,是不是必须使用lambda? >>> def f(x): ... return x+2 ... >>> f(1) 3 >>> f = lambda x:x+2 >>> f(1) 3 >>> (lambda x:x+2)(1) 3 Python def...
目前有的书籍文章常常忽略了上述的条件,仅仅推荐简化表达式,使实践结果与计算值出现矛盾,常给读者造成困惑不解。需说明的是,三端固定输出的稳压集成电路78××(包括79××)系列,外部增设电阻提高输出电压...
是常用的校验码,在早期的通信中运用广泛,因为早期的通信技术不够可靠(不可靠性的来源是通信技术决定的,比如电磁波通信时受雷电等因素的影响),不可靠的通信就会带来‘确认信息’的困惑,书上提到红军和蓝军...
循环神经网络实现语言模型循环神经网络裁剪梯度困惑度实现 循环神经网络 目的是基于当前的输入与过去的输入序列,预测序列的下一个字符。循环神经网络中引入一个隐含层HHH,用HtH_tHt表示HHH在时间步ttt的值。HtH_...
和X创业--走出困惑,开创未来(PPT 21).ppt
DFT的matlab源代码离散傅立叶变换 不使用fft函数的DFT的MATLAB代码 需要特别注意的是,这是一个功能文件而不是脚本,您...如有任何疑问,困惑或反馈,请联系 耐克(Nikesh Bajaj) 热那亚大学和伦敦玛丽皇后大学博士生
用python计算lda语言模型的困惑度并作图
介绍X-window的原理。让你不在那么困惑
打开困惑的钥匙
AngularJS的初学者常常会对$parse和$eval两个内建服务感到有些困惑,今天我们就来说说AngularJS中的$parse和$eval。 总的来说,$parse和$eval都是作用于AngularJS的表达式。 什么是表达式? AngularJS中的表达式就是...
经典的教程,值得一读,困惑的浪漫--高志鹏原创,难得一见的书籍,内容的高度少有企及
科学的困惑与疆界
破解内部审计的困惑与问题--课后测试.docx
WINHEX高级专题教程大全-困惑的浪漫(高志鹏)
战略性新兴产业的困惑和对策考试答案.docx
由于收费,他们的性质令人困惑,这迫使其最小的夸克含量为$$ c \ bar {c} u \ bar {d} $$cc¯ud¯($$ c \ bar {c} d \ bar { u} $$cc¯du¯)。 因此,有必要探索四夸克系统以了解其内部结构。 此外,它们与$$ \ ...
困惑的小人PPT素材下载,关键词:3d小人、白色小人幻灯片插图素材,困惑、疑惑、疑问、问号PPT素材下载,PPTX格式;
高校后扩招期困惑之分析论文.doc