關(guān)于C/C++中的side effect(負(fù)效應(yīng))和sequence point(序列點(diǎn))
不知你在寫code時(shí)是否遇到這樣的問題?int i = 3; int x = (++i) + (++i) + (++i); 問x值為多少?進(jìn)行各種理論分析,并在編譯器上實(shí)踐,然而可能發(fā)現(xiàn)最終的結(jié)果是不正確的,也是不穩(wěn)定的,不同的編譯器可能會(huì)產(chǎn)生不同的結(jié)果。這讓人很頭疼。結(jié)果到底是啥呢?對(duì)于此題的答案,一句話,Theresult is undefined! 詳細(xì)解釋待我慢慢說來。
大家知道,通常而言,我們寫的計(jì)算機(jī)程序都是從上到下,從左到右依次執(zhí)行。然而,我只是說通常,因?yàn)樵诰幾g的過程中,compiler并不僅僅是把source code翻譯成binary code就算了,這個(gè)過程里面可能還會(huì)對(duì)代碼進(jìn)行優(yōu)化,這種優(yōu)化可能帶來的結(jié)果是:代碼或者表達(dá)式evaluation的順序可能發(fā)生變化。這可是一個(gè)非常嚴(yán)重的問題,當(dāng)某個(gè)表達(dá)式帶有side-effect(比如改變了一個(gè)變量的值),那么它的執(zhí)行順序直接影響到了程序執(zhí)行的結(jié)果。
為了保證程序執(zhí)行具有確定性的結(jié)果,C++標(biāo)準(zhǔn)引入Sequence Point這個(gè)概念,按照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.
簡(jiǎn)而言之,Sequence Point就是這么一個(gè)位置,在它之前所有的side effect已經(jīng)發(fā)生,在它之后的所有side effect仍未開始,而兩個(gè)Sequence Point之間所有的表達(dá)式或者代碼執(zhí)行的順序是未定義的!
而C++標(biāo)準(zhǔn)又進(jìn)一步規(guī)定了Sequence Point出現(xiàn)的5種情況:
1、At the end of a full expression
在一個(gè)完整的表達(dá)式末尾是Sequence Point,所謂完整的表達(dá)式是指這個(gè)表達(dá)式不是另外一個(gè)表達(dá)式的一部分。所以如果有f(); g();這樣兩條語(yǔ)句,f()和g()是兩個(gè)完整的表達(dá)式,f()的Side Effect必定在g()之前發(fā)生。
2、After the evaluation of all function arguments in a function call and before execution of any expressions in the function body
調(diào)用一個(gè)函數(shù)時(shí),在所有準(zhǔn)備工作做完之后、函數(shù)調(diào)用開始之前是Sequence Point。比如調(diào)用foo(f(), g())時(shí),foo、f()、g()這三個(gè)表達(dá)式哪個(gè)先求值哪個(gè)后求值是Unspecified,但是必須都求值完了才能做最后的函數(shù)調(diào)用,所以f()和g()的Side Effect按什么順序發(fā)生不一定,但必定在這些Side Effect全部作用完之后才開始調(diào)用foo函數(shù)。
3、After copying of a returned value and before execution of any expressions outside the function
函數(shù)即將返回時(shí)是Sequence Point,因?yàn)楹瘮?shù)返回時(shí)必然會(huì)結(jié)束掉一個(gè)完整的表達(dá)式。
4、After evaluation of the first expression in a&&b, a||b, a?b:c, or a,b
條件運(yùn)算符?:、逗號(hào)運(yùn)算符、邏輯與&&、邏輯或||的第一個(gè)操作數(shù)求值之后是Sequence Point。如條件運(yùn)算符和逗號(hào)運(yùn)算符,條件運(yùn)算符要根據(jù)表達(dá)式1的值是否為真決定下一步求表達(dá)式2還是表達(dá)式3的值,如果決定求表達(dá)式2的值,表達(dá)式3就不會(huì)被求值了,反之也一樣,逗號(hào)運(yùn)算符也是這樣,表達(dá)式1求值結(jié)束才繼續(xù)求表達(dá)式2的值。
5、After the initialization of each base and member in the constructor initialization list
在一個(gè)完整的聲明末尾是Sequence Point,所謂完整的聲明是指這個(gè)聲明不是另外一個(gè)聲明的一部分。比如聲明int a[10], b[20];,在a[10]末尾是Sequence Point,在b[20]末尾也是。
經(jīng)過以上說明,大家已有所了解,現(xiàn)在回到我們的題目:int x = (++i) + (++i) + (++i); 整個(gè)的語(yǔ)句里面,只有1個(gè)Sequence Point,也就是語(yǔ)句的結(jié)束點(diǎn),對(duì)于右邊表達(dá)式的計(jì)算順序沒有任何的規(guī)定,顯然,各種編譯器都可以按照他們覺得“舒服”的方式來進(jìn)行計(jì)算,這樣的代碼,如果只要求在特定的平臺(tái)或者編譯器運(yùn)行,那么帶來的可能只是可讀性差的問題,但如果考慮跨平臺(tái)或者編譯器的情況,那么就是完完全全的錯(cuò)誤!
另外,需要特別注意的是,對(duì)于賦值號(hào)(assignment operator),C++也沒有把它定義成Sequence Point,也就說這樣的語(yǔ)句:buffer[i] = i++;同樣是undefined的,因?yàn)?,?duì)于等號(hào)左右兩邊的表達(dá)式運(yùn)算順序,你并不能有任何的假定。
上一篇:C語(yǔ)言中基礎(chǔ)小問題詳細(xì)介紹
欄 目:C語(yǔ)言
下一篇:成員函數(shù)的重載、覆蓋與隱藏詳細(xì)解析
本文標(biāo)題:關(guān)于C/C++中的side effect(負(fù)效應(yīng))和sequence point(序列點(diǎn))
本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/4026.html
您可能感興趣的文章
- 04-02c語(yǔ)言沒有round函數(shù) round c語(yǔ)言
- 01-10深入理解C++中常見的關(guān)鍵字含義
- 01-10使用C++實(shí)現(xiàn)全排列算法的方法詳解
- 01-10深入Main函數(shù)中的參數(shù)argc,argv的使用詳解
- 01-10c++中inline的用法分析
- 01-10如何尋找數(shù)組中的第二大數(shù)
- 01-10用C++實(shí)現(xiàn)DBSCAN聚類算法
- 01-10全排列算法的非遞歸實(shí)現(xiàn)與遞歸實(shí)現(xiàn)的方法(C++)
- 01-10C++大數(shù)模板(推薦)
- 01-10淺談C/C++中的static與extern關(guān)鍵字的使用詳解


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 04-02c語(yǔ)言函數(shù)調(diào)用后清空內(nèi)存 c語(yǔ)言調(diào)用
- 04-02func函數(shù)+在C語(yǔ)言 func函數(shù)在c語(yǔ)言中
- 04-02c語(yǔ)言的正則匹配函數(shù) c語(yǔ)言正則表達(dá)
- 04-02c語(yǔ)言用函數(shù)寫分段 用c語(yǔ)言表示分段
- 04-02c語(yǔ)言中對(duì)數(shù)函數(shù)的表達(dá)式 c語(yǔ)言中對(duì)
- 04-02c語(yǔ)言編寫函數(shù)冒泡排序 c語(yǔ)言冒泡排
- 04-02c語(yǔ)言沒有round函數(shù) round c語(yǔ)言
- 04-02c語(yǔ)言分段函數(shù)怎么求 用c語(yǔ)言求分段
- 04-02C語(yǔ)言中怎么打出三角函數(shù) c語(yǔ)言中怎
- 04-02c語(yǔ)言調(diào)用函數(shù)求fibo C語(yǔ)言調(diào)用函數(shù)求
隨機(jī)閱讀
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 01-10C#中split用法實(shí)例總結(jié)
- 04-02jquery與jsp,用jquery
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 01-10delphi制作wav文件的方法
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載