浅析C++中的序列点[VC/C++编程]
本文“浅析C++中的序列点[VC/C++编程]”是由七道奇为您精心收集,来源于网络转载,文章版权归文章作者所有,本站不对其观点以及内容做任何评价,请读者自行判断,以下是其具体内容:
int i = 3;
i = i++;
cout << i;
后果是什么?有人大概会说是3,也有人大概会说是4,更多的人在骂出题的人白痴,但这语句毕竟有何问题呢?未必每个人都清楚.
有些人大概即刻会说,这是“未定义行为”.没错,这是一个典型的未定义行为.i = i++这个表达式合乎C++语法,可以顺利编译通过,但是履行的后果,尺度说“未定义”.为什么是“未定义”,深究起来,要从序列点说起.
序列点是程序中这样的一些点:通俗地说,履行至此,之前的语句都已经完好履行干净履行完了,之后的语句还完好没开始履行;更常见、更严谨但略晦涩的说法是,之前的语句对现场环境的改变已经全部完成,之后的语句对现场环境的改变还没有开始.啥是现场环境呢?就是程序履行到某一点的那个状况,包含变量的内容、文件的内容等.
这跟最开始那个例子有什么关系呢?关键的问题来了:尺度规定,两个序列点之间,程序履行的次序可以是肆意的.没错,正如你猜的那样,C++尺度规定一个完好的表达式完毕之后有一个序列点,而例子中i = i++是位于两个序列点之间的.编译器可以先算完i++,再写后果给i,也可以先将i = i,再令i++.按前面的办法算,i先自增变成4,然后i++返回3,于是i被赋值为3;按后一种办法算,i先被赋值为3,随后自增变成4.尺度说了,这两种处理办法,编译器你爱选那种就选哪类,随便.假如谁写的程序像这样依靠履行的次序,让他自己哭去!
等等,有人要问了,++的优先级难倒不是高于=吗?明显应当先履行++啊.这里有个概念的问题,前一段说的编译器先算i = i,毫不是说令=的优先级比++还高了.假如那样的话,表达式将变成 (i = i)++,也就是i.operator = (i). operator ++,履行++的主体变成i = i这个表达式的返回值了.上一段所说的先计算i = i,实际上还是先计算i++,只不过是先返回了i的值,然后推迟了将i自增1的操作先去干别的(i = i)去了,回头再来给i自增1.
——“什么,你说先干别的就先干别的,凭什么!”
嗯,我再反复一遍,尺度规定,两个序列点之间,程序履行的次序可以是肆意的.
——“不是吃饱了撑的嘛,尺度搞这个干啥?严峻按照次序履行不就完了嘛”.
C++尺度弄这么复杂自然是有原理的.C++是极其器重履行效率的语言,这样做给了编译器优化的空间.比方考虑
int j = i++;
假如非得把i++履行干净了再干别的,那就不得不 temp = i; i += 1; j = i; .假如答应编译器打乱次序履行呢,直接 j = i; i +=1; 就行了,省了一个temp倒一次的历程.
多说一句,一些更高层的语言,不是像C++这种极其器重效率的,比方Java,上面的例子就完好没有问题.Java完好不答应你编译器乱搞,上面那个例子,在Java中一定是先把i++完好履行干净了返回3,再举行赋值,赋值完之后不会再有别的操作了,所今后果一定是3.
若何避免由序列点造成的这种未定义行为,有一句经典但有点晦涩的编程法则:“在相邻的两个序列点之间,一个对象只答应被改正一次,并且假如一个对象被改正则在这两个序列点之间只能为了肯定该对象的新值而读一次”.其实懂得了序列点具体是怎么回事,这个法则应当就很简单懂得了.由于序列点之间程序履行次序不肯定,一个对象被改正多次的话最后留下的是哪次的后果就不肯定.别的假如一个对象同时存在读取和改正,只有按照读取的后果来改正才是合理的,不然就会呈现是先改完再读还是先读完再改的混乱.
最后再说一下最新的C++2003尺度中定义的序列点(具体阐明请参考尺度):
·完好声明之后
·完好表达式之后
·进入函数时与退出函数时
·|| && ?: , 四个操作符的第一个操作数之后
最后一个仿佛有点奇特,为啥 + - 操作符之前就没有序列点,|| &&之前就有呢?a+b之间没有序列点而a||b之间就有,不公道啊.
嗯,你猜的没错,是为了短路.
不过如果手建重载了默许的||和&&,他们可就视同普通函数,不会在第一个操作数之后有序列点了,牢记.
以上是“浅析C++中的序列点[VC/C++编程]”的内容,如果你对以上该文章内容感兴趣,你可以看看七道奇为您推荐以下文章:
本文地址: | 与您的QQ/BBS好友分享! |