關於C/C++中的side effect(負效應)和sequence point(序列點)。本站提示廣大學習愛好者:(關於C/C++中的side effect(負效應)和sequence point(序列點))文章只能為提供參考,不一定能成為您想要的結果。以下是關於C/C++中的side effect(負效應)和sequence point(序列點)正文
不知你在寫code時能否碰到如許的成績?int i = 3; int x = (++i) + (++i) + (++i); 問x值為若干?停止各類實際剖析,並在編譯器上理論,但是能夠發明終究的成果是不准確的,也是不穩固的,分歧的編譯器能夠會發生分歧的成果。這讓人很頭疼。成果究竟是啥呢?關於此題的謎底,一句話,Theresult is undefined! 具體說明待我漸漸說來。
年夜家曉得,平日而言,我們寫的盤算機法式都是從上到下,從左到右順次履行。但是,我只是說平日,由於在編譯的進程中,compiler其實不僅僅是把source code翻譯成binary code就算了,這個進程外面能夠還會對代碼停止優化,這類優化能夠帶來的成果是:代碼或許表達式evaluation的次序能夠產生變更。這可是一個異常嚴重的成績,當某個表達式帶有side-effect(好比轉變了一個變量的值),那末它的履行次序直接影響到了法式履行的成果。
為了包管法式履行具有肯定性的成果,C++尺度引入Sequence Point這個概念,依照ISO/IEC的界說:
At certain specified points in the execution sequence called sequence points. All side effects of previous evaluations shall be complete and no side effects of subsequent evaluations shall have taken place.
簡而言之,Sequence Point就是這麼一個地位,在它之前一切的side effect曾經產生,在它以後的一切side effect仍未開端,而兩個Sequence Point之間一切的表達式或許代碼履行的次序是不決義的!
而C++尺度又進一步劃定了Sequence Point湧現的5種情形:
1、At the end of a full expression
在一個完全的表達式末尾是Sequence Point,所謂完全的表達式是指這個表達式不是別的一個表達式的一部門。所以假如有f(); g();如許兩條語句,f()和g()是兩個完全的表達式,f()的Side Effect一定在g()之前產生。
2、After the evaluation of all function arguments in a function call and before execution of any expressions in the function body
挪用一個函數時,在一切預備任務做完以後、函數挪用開端之前是Sequence Point。好比挪用foo(f(), g())時,foo、f()、g()這三個表達式哪一個先求值哪一個後求值是Unspecified,然則必需都求值完了能力做最初的函數挪用,所以f()和g()的Side Effect按甚麼次序產生紛歧定,但一定在這些Side Effect全體感化完以後才開端挪用foo函數。
3、After copying of a returned value and before execution of any expressions outside the function
函數行將前往時是Sequence Point,由於函數前往時必定會停止失落一個完全的表達式。
4、After evaluation of the first expression in a&&b, a||b, a?b:c, or a,b
前提運算符?:、逗號運算符、邏輯與&&、邏輯或||的第一個操作數求值以後是Sequence Point。如前提運算符和逗號運算符,前提運算符要依據表達式1的值能否為真決議下一步求表達式2照樣表達式3的值,假如決議求表達式2的值,表達式3就不會被求值了,反之也一樣,逗號運算符也是如許,表達式1求值停止才持續求表達式2的值。
5、After the initialization of each base and member in the constructor initialization list
在一個完全的聲明末尾是Sequence Point,所謂完全的聲明是指這個聲明不是別的一個聲明的一部門。好比聲明int a[10], b[20];,在a[10]末尾是Sequence Point,在b[20]末尾也是。
經由以上解釋,年夜家已有所懂得,如今回到我們的標題:int x = (++i) + (++i) + (++i); 全部的語句外面,只要1個Sequence Point,也就是語句的停止點,關於左邊表達式的盤算次序沒有任何的劃定,明顯,各類編譯器都可以依照他們認為“舒暢”的方法來停止盤算,如許的代碼,假如只需求在特定的平台或許編譯器運轉,那末帶來的能夠只是可讀性差的成績,但假如斟酌跨平台或許編譯器的情形,那末就是完完整全的毛病!
別的,須要特殊留意的是,關於賦值號(assignment operator),C++也沒有把它界說成Sequence Point,也就說如許的語句:buffer[i] = i++;異樣是undefined的,由於,關於等號閣下雙方的表達式運算次序,你其實不能有任何的假定。