TITLE: sequence points in C and C++ EL = Eric Jui-Lin Lu SYC = cheung@mathcs.emory.edu (Shun Yan Cheung) SC = clamage@Eng.Sun.COM (Steve Clamage), 15 Sep 95 JE = ehrhart.jeffrey@mayo.edu (Jeffrey T. Ehrhart) writes: EL: I thought, when "i = i++" is being evaluating, the value of i, which is 1 at that moment, is assigned to i. So, i is 1. And then i is increaed by 1. So, the output is 2. But it's wrong. The output is 1. What's wrong? Is the result compiler-dependent? SYC: After reading many of the replies to this question, I wonder how well C (not C++) is taught in schools/universities or books. Weird as it may looks, i = i++ is very well defined, just follow the rules of the language: SC: In particular, look at a quote from the ANSI/ISO C Standard 9899-1990, section 6.3 "Expressions", paragraph 2: "Between the previous and next sequence point an 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." In the expression i = i++ we have no sequence points, and 'i' is modified twice. This violates a "shall" clause, and consequently has undefined behavior which the compiler is not required to diagnose. (In particular, there is a sequence point at a semicolon, but assignment does not create a sequence point. At best, there can be a sequence point before this expression and after this expression, but there is no sequence point in this expression.) Lest you think this was some strange addition to C, take a look at K&R1 (1978) reference manual section 7 (p 185). It says the order of evaluation of expressions and the order in which side effects take place is unspecified. The ANSI C committee clarified what this meant by introducing the notion of sequence points. SYC: 1. apply the priority rules: i = i++ evaluate as: i = (i++) 2. Evaluate the expression, i++ first: i++ evaluates to 1 (Ignore the side effect that i = 2 after the evaluation. Because in the assignment expression, it will use the result of i++, and not the value of i) Therefore: i = (i++) is evaulated as: i = 1 SC: Apart from the above rule which states explicitly that the expression has undefined semantics, your reasoning is flawed. Variable "i" is incremented by the "++", and is also assigned to by the "=". No language rule says whether the incremented value is applied to "i" before or after the assignment. The precedence rules affect grouping, but do not create a total ordering on evaluation sequences. Example: i = j++ // well-defined, assuming i and j are disjoint objects In this expression, "i" gets (1 + the original value of j), and "j" also gets that value. Question: does "j" get its new value before or after "i" does? Answer: that is unspecified. The compiler may choose to do either one first. The only requirement is that both updates occur after the previous sequence point and before the next sequence point. Notice that these to sequences (among others) satisfy all the requirements on "i=j++", and the compiler could generate code equivalent to either sequence: int temp = j; int temp = j; i = temp + 1; j = j + 1; j = j + 1; i = temp + 1; When "i" and "j" are disjoint, it doesn't matter which update happens first. Now change "j" to "i" and you see that if you can't tell which update happens first, you cannot predict the final value of "i". As it happens, the language standard spares you the trouble, and says the expression has no defined meaning. JE: What is meant by "sequence point"? Does that mean that the following statement is also results in an undefined value for 'i' ? a = (i++ * 2) - i++; SC: Yes, that is also undefined. The only sequence point here is the semicolon. A sequence point is place in the source code such that all side effects in expressions lexically before the sequence point have already occured, and no side effects in expressions following the sequence point have yet occured. The C++ definition of sequence point is not identical to the C definition, and is still being worked on by the C++ committee. The definition in the draft is as follows: ---------------------- Define a full­expression as an expression that is not a subexpression of another expression. There is a sequence point at the completion of evaluation of each full­expression. When calling a function (whether or not the function is inline), there is a sequence point after the evaluation of all function arguments (if any) which takes place before execution of any expressions or statements in the function body. There is also a sequence point after the copying of a returned value and before the execution of any expressions outside the function. Several contexts in C++ cause evaluation of a function call, even though no corresponding function call syntax appears in the translation unit. [Example: evaluation of a new expression invokes one or more allocation and constructor functions; see 5.3.4. For another example, invocation of a conversion function (12.3.2) can arise in contexts in which no function call syntax appears. ] The sequence points at function­entry and function­exit (as described above) are features of the function calls as evaluated, whatever the syntax of the expression that calls the function might be. In the evaluation of each of the expressions a && b a || b a ? b : c a , b using the builtin meaning of the operators in these expressions (5.14, 5.15, 5.16, 5.18) there is a sequence point after the evaluation of the first expression 9) .