sequence points in c
An important thing to note about sequence points is that they are not global, but rather should be regarded as a set of local constraints. For example, in the statement
a = f1(x++) + f2(y++);
There is a sequence point between the evaluation of x++ and the call to f1, and another sequence point between the evaluation of y++ and the call to f2. There is, however, no guarantee as to whether x will be incremented before or after f2 is called, nor whether y will be incremented before or after x is called. If f1 changes y or f2 changes x, the results will be undefined (it would be legitimate for the compiler's generated code to e.g. read x and y, increment x, call f1, check y against the previously-read value, and--if it changed--go on a rampage seeking out and destroying all Barney videos and merchandise; I don't think any real compilers generate code that would actually do that, alas, but it would be permitted under the standard).
When a sequence point occurs, it basically means that you are guaranteed that all previous operations are complete.
Changing a variable twice without an intervening sequence point is one example of undefined behaviour.
For example, i = i++;
is undefined because there's no sequence point between the two changes to i
.
Note that it's not just changing a variable twice that can cause a problem. It's actually a change involved with any other use. The standard uses the term "value computation and side effect" when discussing how things are sequenced. For example, in the expression
a = i + i++
, thei
(value computation) andi++
(side effect) may be done in arbitrary order.
Wikipedia has a list of the sequence points in the C and C++ standards although the definitive list should always be taken from the ISO standard. From C11 appendix C (paraphrased):
The following are the sequence points described in the standard:
- Between the evaluations of the function designator and actual arguments in a function call and the actual call;
- Between the evaluations of the first and second operands of the operators
&&
,||
, and,
; - Between the evaluations of the first operand of the conditional
?:
operator and whichever of the second and third operands is evaluated; - The end of a full declarator;
- Between the evaluation of a full expression and the next full expression to be evaluated. The following are full expressions:
- an initializer;
- the expression in an expression statement;
- the controlling expression of a selection statement (
if
orswitch
); - the controlling expression of a
while
or do statement; - each of the expressions of a
for
statement; - the expression in a return statement.
- Immediately before a library function returns;
- After the actions associated with each formatted input/output function conversion specifier;
- Immediately before and immediately after each call to a comparison function, and also between any call to a comparison function and any movement of the objects passed as arguments to that call.