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写的,就会明白了。 |