嗯,这个帖子讲得很深刻。很多概念不是属于入门知识,适合有一定基础的人进阶看看。可以看出楼主下了不少功夫~~
不过关于 y = (4 + x++) + (6 + x++); 这个語句,我有几点补充。
当然楼主也表明,这个語句本身有些毛病,不过这个毛病有点比楼主指出的要大。(我这是吹毛求疵,一般只有语言律师会这么咬文嚼字。)
标准第五章引论的第四条(见下5-4)里说了“(我翻译一下)除非特别注明,对诸如运算符的运算以及表达式的子表达式的评估(evaluation)顺序、副作用的发生顺序是未明确(unspecified)的。在前后两个顺序点之间评估一个表达式时,对一个纯量对象(scalar object)储存值的改动至多出现一次。此外,对该对象原来值的访问应仅是为了确定其新值。对所有容许顺序推定的完全表达式的子表达式,本条目的规定均生效。违反的表达式的行为是未定义(undefined)的。”
关于“未明确”和“未定义”的概念,是在第一章第九节(见 1.9.3 和 1.9.4)中描述的,1.9.4 中指出“(我还是翻译一下)在本国际标准中某些操作被描述为未定义(例如,对空指针(null pointer)的解引用(dereferencing))[注:本国际标准对含有未定义行为的程序的行为不施加任何限制。]”
由此可见,那个語句,在两个顺序点之间,对 x 的值修改了两次。因此是未定义的。楼主说 “C++会保证程序执行到下一条语句之前,将 x 的值递增两次”,其实这个标准保证不了。编译器对这个語句做任何处理,都是符合标准的(因为标准没有任何限制)。
下面援引标准上的一些原文,以帮助大家深入学习(包括楼主介绍的一些概念,这个只有原文才够权威~~):
1.9.3:Certain other aspects and operations of the abstract machine are described in this International Standard as unspecified (for example, order of evaluation of arguments to a function). Where possible, this International Standard defines a set of allowable behaviors. These define the nondeterministic aspects of the abstract machine. An instance of the abstract machine can thus have more than one possible execution sequence for a given program and a given input.
1.9.4: Certain other operations are described in this International Standard as undefined (for example, the effect of dereferencing the null pointer). [Note: this International Standard imposes no requirements on the behavior of programs that contain undefined behavior. ]
1.9.7: Accessing an object designated by a volatile lvalue (3.10), modifying an object, calling a library I/O function, or calling a function that does any of those operations are all side effects, which are changes in the state of the execution environment. Evaluation of an expression might produce side effects. 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.
1.9.11-1: At sequence points, volatile objects are stable in the sense that previous evaluations are complete and subsequent evaluations have not yet occurred.
1.9.12: A full-expression is an expression that is not a subexpression of another expression. If a language construct is defined to produce an implicit call of a function, a use of the language construct is considered to be an expression for the purposes of this definition.
1.9.13: [Note: certain contexts in C++ cause the evaluation of a full-expression that results from a syntactic construct other than expression (5.18). For example, in 8.5 one syntax for initializer is
( expression-list )
but the resulting construct is a function call upon a constructor function with expression-list as an argument list; such a function call is a full-expression. For example, in 8.5, another syntax for initializer is
= initializer-clause
but again the resulting construct might be a function call upon a constructor function with one assignment- expression as an argument; again, the function call is a full-expression. ]
1.9.14: [Note: the evaluation of a full-expression can include the evaluation of subexpressions that are not lexically part of the full-expression. For example, subexpressions involved in evaluating default argument expressions (8.3.6) are considered to be created in the expression that calls the function, not the expression that defines the default argument. ]
1.9.16: There is a sequence point at the completion of evaluation of each full-expression.
5-1: [Note: Clause 5 defines the syntax, order of evaluation, and meaning of expressions. An expression is a sequence of operators and operands that specifies a computation. An expression can result in a value and can cause side effects.
5-4: Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified. Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored. The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined. [Example:
i = v[i++]; // the behavior is unspecified
i = 7, i++, i++;// i becomes 9
i = ++i + 1; // the behavior is unspecified
i = i + 1; // the value of i is incremented
—end example]
[
本帖最后由 pangding 于 2010-12-6 21:13 编辑 ]