THEBEST 回復于:2004-04-22 22:09:43 |
no one can help? |
THEBEST 回復于:2004-04-27 17:16:10 |
唉好失望啊. |
lenovo 回復于:2004-04-27 20:11:05 |
你看哪里看來的?
把原文貼出來。讓大家幫你看看。 就給一個概念,誰知道是怎么回事呀。 |
THEBEST 回復于:2004-04-27 20:30:16 |
不知是:
"C++規定兩個sequence point之間,一個值只能被寫一次"正確還是: "C++規定一個sequence point之間,一個值只能被寫一次"正確. |
chg.s 回復于:2004-04-27 21:44:32 |
表達式的計算分為兩種,一種是有副作用的計算,如:
(++x)+y 一種是無副作用的計算,如: x*y 有副作用的計算中,子表達式的計算順序是重要的。例如 (++x)*(x+1) 當x=0時,如果先算++x,上式計算結果為2,如果先算x+1,上式計算結果為1。 再如,對函數g(int, int)的調用g(x, ++x), 當x=1,這個調用是g(1, 2)還是g(2, 2)? 所謂“順序點”,和表達式的副作用緊密相關。再看這個例子: (++i) + (++j) 這個表達式的計算,有兩個副作用: i自增1; j自增1; 但是到底哪一個先發生?答案是:任何答案都不對。 為什么?因為標準并不定義副作用發生的順序。標準只保證,一個表達式的全部副作用,不在達到該表達式緊鄰的前一順序點前發生,并且一定在達到該表達式緊鄰的下一個順序點之前發生完畢。 一個順序點,被定義為程序執行過程中的這樣一個點:該點前的表達式的所有副作用,在程序執行到達該點之前發生完畢;該點后的表達式的所有副作用,在程序執行到該點時尚未發生。 (++i) + (++j)這個表達式本身不包含順序點,所以i++,j++這兩個“副作用”到底誰先發生,根據標準,是未定義的。如果給這個表達式加上順序點,如: ;(++i) + (++j); 標準只保證,這兩個副作用在整個表達式求值完成前(即到達后面的順序點";"前)都會發生,并且不會在上一個語句執行完畢之前發生。 標準還規定,兩個相鄰順序點之間,對某一表達式求值,最多只能造成任一特定對象的值被更改一次。如果表達式求值過程會更改某對象的值,那么要求更改前的值被讀取的唯一目的,只能是用來確定要存入的新值。 例如下面的表達式,按照標準規定,執行結果是未定義的: (i++)+(i++) 這個表達式本身不包含任何順序點,但是對這個表達式求值,按照運算符定義,將更改i兩次,違反了“一次更改”的要求。 再看下面的表達式,按照標準規定,執行結果也是未定義的: x[i]=i++ 這個表達式本身不包含任何順序點,雖然i的值只更改了一次,但是x[i]這個左值中,i被讀取,用于確定數組中被修改的元素的下標。這次對i求值和i++肯定位于同一對順序點之間,該表達式求值過程更改了i的值,x[i]中讀取i卻不是為了確定i的新值,這違反了“讀取只能用于確定新值”規定。 任何對相鄰順序點間表達式求值的多個副作用發生的順序進行假設,或者違反上述“一次更改、讀取僅用于確定新值”規定的代碼,其執行結果都是未定義的。這里所說的“未定義”,通常比“不可移植”更嚴重,可以認為是“錯誤”的同意詞。 通常我們認為,標準對“順序點”及其語義的定義,是為了嚴謹地定義C/C++的表達式和求值過程,并不是為了讓程序員通過對順序點的掌握,(過分地)利用表達式求值的副作用。實際工作中,我們完全可以通過引入中間變量,避開“順序點”這樣容易出錯,也極大地降低代碼可讀性的“邊緣概念”。 |
THEBEST 回復于:2004-04-28 22:55:54 |
為什么說:
(++x)+y 有副作用 (++i) + (++j) 有兩個副作用呢? 我覺得這兩個表達式不管如何計算也不會影響結果吧? 哪來副作用呢? (++x)*(x+1) 這種表達式說有副作用還可以理解,畢竟兩個子表達式的計算順序會影響表達式的結果. 能解釋一下這里的副作用嗎? 我覺得副作用就是表達式的計算順序會影響表達式的結果.對不對? |
chg.s 回復于:2004-04-29 09:56:50 |
[quote:016cb14df4="THEBEST"]我覺得副作用就是表達式的計算順序會影響表達式的結果.對不對?[/quote:016cb14df4]
不對。當你寫出違反順序點定義的表達式的時候,子表達式求值的順序會影響表達式的結果,這種情況正是標準希望通過“順序點”的定義來避免的情況。 如果你不違反順序點的定義,子表達式求值的順序則不會影響整個表達式的結果,但是一個符合順序點定義,計算順序不影響其結果的表達式,仍然可以有副作用。所謂副作用,是相對傳統意義上的“表達式”來說的。 例如,傳統表達式的計算過程,運算符不會令參與計算的變量本身的值發生改變;而C/C++語言的表達式中由于++, --等運算符的介入,表達式求值可能導致參與計算的變量本身的值發生改變。這就是一種可能的副作用。 [quote:016cb14df4="THEBEST"]為什么說: (++x)+y 有副作用 (++i) + (++j) 有兩個副作用呢? 我覺得這兩個表達式不管如何計算也不會影響結果吧? 哪來副作用呢?[/quote:016cb14df4] 如果單從表達式本身的計算結果看,這兩個表達式的副作用當然不會影響整個表達式的值;在C語言中對表達式 (++i) + (++j) 求值,會使i的值加一,j的值加一。你不對這兩件事發生的順序作假設,而只關心整個表達式的最終結果。從這個意義上說,你寫的這個表達式符合順序點的定義,因而它的計算結果,按照標準定義,是沒有歧義的。整個表達式的“計算結果沒有歧義”不等于說它“沒有副作用”,i和j的值發生改變正是這個表達式求值的副作用。 |
THEBEST 回復于:2004-04-29 12:22:27 |
你說的"順序點"的概念怎么我理解起來就像是;一樣呢?
比如一個語句的結束就是一個順序點產生,而這個語句前面的;(順序點)就表示下一個語句產生.....是不是這樣呢? [quote:fdda1bace2]如果表達式求值過程會更改某對象的值,那么要求更改前的值被讀取的唯一目的,只能是用來確定要存入的新值。 [/quote:fdda1bace2] 是[color=blue:fdda1bace2]更改前[/color:fdda1bace2]的值被讀取的唯一目的嗎? x[i]=i++ 這個表達式中x[i] 中讀取i是更改后啊. 如何理解"更改前的值被讀取只能是為了確定要存入的新值"呢? |
chg.s 回復于:2004-04-29 12:53:10 |
唉……看來還是我表達能力不行啊。算了我們私下說吧,再這么討論下去非得讓斑竹當成版聊帖子刪除了不可。 |
lenovo 回復于:2004-04-29 14:42:59 |
沒關系。說得很好。
我對它們的概念也就懂一點點, 也不是很清楚。受教了。 呵呵,如果不影響你繼續學別的內容, 慢慢理解好了。 |
THEBEST 回復于:2004-04-29 17:17:57 |
[quote:74fd0692cf]TITLE: What is a sequence point?
RESPONSE: jimad@microsoft.com (Jim Adcock) Section 3.3 defines multiple aclearcase/" target="_blank" >ccesses to one variable for modification within an expression [between two sequence points] as being an unconstrained error. RESPONSE: mayoff@sylvester.cc.utexas.edu (rob) Please define `sequence point'. RESPONSE: jimad@microsoft.com (Jim Adcock), Microsoft Corporation, 12 Jul 93 The ANSI/ISO C++ standardization effort is being based on two documents, both highly recommended. One is the ARM, the other is X3.159-1989, the ANSI C standards document [or equivalently it's ISO counterpart] From the ANSI-C doc, 2.1.2.3.33 "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 take place. Appendix B lists the following as sequence points, quote: * The call to a function, after the arguments have been evaluated. * The end of the first operand of the following operators: logical AND &&; logical OR ||; conditional ? ; comma , . * The end of a full expression: an initializer; the expression in an expression statement; the controlling expression of a selection statement (if or switch); the controlling expression of a while or do statement; each of the three expressions of a for statement; the expression in a return statement. unquote. [/quote:74fd0692cf] |
chg.s 回復于:2004-04-30 09:30:05 |
算了,既然斑竹發話說沒有關系,那我就再發最后一篇來解釋這個問題。本來是希望用最簡短的文字解釋清楚,沒想到越是想簡潔越是沒說清。
C語言中,只包含一個表達式的語句,如 x = (i++) * 2; 稱為“表達式語句”。表達式語句結尾的";"是C標準定義的順序點之一,但這不等同于說所有的";"都是順序點,也不是說順序點只有這一種。下面就是標準中定義的順序點: 函數調用時,實參表內全部參數求值結束,函數的第一條指令執行之前(注意參數分隔符“,”不是順序點); &&操作符的左操作數結尾處; ||操作符的左操作數結尾處; ?:操作符的第一個操作數的結尾處; 逗號運算符; 表達式求值的結束點,具體包括下列幾類:自動對象的初值計算結束處;表達式語句末尾的分號處;do/while/if/switch/for語句的控制條件的右括號處;for語句控制條件中的兩個分號處;return語句返回值計算結束(末尾的分號)處。 定義順序點是為了盡量消除編譯器解釋表達式時的歧義,如果順序點還是不能解決某些歧義,那么標準允許編譯器的實現自由選擇解釋方式。理解順序點還是要從定義它的目的來下手。 再舉一個例子: y = x++, x+1; 已知這個語句執行前x=2,問y的值是多少? 逗號運算符是順序點。那么該表達式的值就是確定的,是4,因為按照順序點的定義,在對x+1求值前,順序點","前的表達式——x++求值的全部副作用都已發生完畢,計算x+1時x=3。這個例子中順序點成功地消除了歧義。 注意這個歧義是怎樣消除的。因為中間的順序點使“相鄰順序點間對象的值只更改一次”的條件得到滿足。 y = (x++) * (x++), 執行前x=2, y=? 答案是,因為這個表達式本身不包含順序點,順序點未能消除歧義,編譯器生成的代碼使y取4, 6(以及更多的一些可能值)都是符合標準定義的,程序員自己應為這個不符合順序點定義的表達式造成的后果負責。 我對我自己的表達能力欠佳表示抱歉,但我的確不準備對這個問題再做更多的解釋。我愿意引用《Expert C Programming》中的一段話,來給自己找一個下臺階: However, the problem with standards manuals is that they only make sense if you already know what they mean. If people write them in English, the more precise they try to be, the longer, duller and more obscure they become. If they write them using mathematical notation to define the language, the manuals become inaccessible to too many people. 自然語言本身的不精確,往往容易造成越解釋越不清楚的現象,而精確的數學語言,又已經超過包括我在內的大多數人的理解和應用能力。 謝謝the best提供的這個機會來檢驗對知識點的理解程度;也謝謝斑竹對這個討論的支持。 |
THEBEST 回復于:2004-04-30 12:49:27 |
chg.s 總是這么謙虛,搞的我都不好意思再糾纏下去.
不過你也解釋的很多了,不是你表達能力差可能是我的IQ不及格吧.:) "自然語言本身的不精確,往往容易造成越解釋越不清楚的現象" 很好! |
我不懂C++ 回復于:2004-06-29 11:46:02 |
chg.s C++不錯。
在C++里面我們寫一個表達式,我們認為只有一個目的: i=j++;//目的是為了給i賦值 func(i++);//目的是為了調用函數 所以j被加1和i被加1這樣的結果,我們認為是“副作用”。這就好比你吃藥殺葡萄球菌,但是把大腸桿菌也殺了,這就是副作用。 我們再看一個表達式 j=(i++)+(i++); i++這個式子的意思大家都知道,就是取i過去的值,然后把i加1。那么編譯器開始分析這個式子了。 它可以這樣做:取i的值,然后再取i的值(加1的事情當然要做,可是沒說什么時候),然后把這兩個i加起來,再給i做兩次加1操作 也可以這樣做:取i的值,然后給i加1,然后再取i的值,... 總之,不同的解釋方法,結果不同,你去寫這樣的表達式,就是玩火。 不知道我有沒有把這兩個概念解釋清楚,如果大家理解了,再去看chg.s寫的,就會明白了。 |