Undefined behavior and sequence points

sequence point c
sequence-point warning
undefined behavior in c
c++ parameter evaluation order
order of evaluation
order of evaluation in c language

What are "sequence points"?

What is the relation between undefined behaviour and sequence points?

I often use funny and convoluted expressions like a[++i] = i;, to make myself feel better. Why should I stop using them?

If you've read this, be sure to visit the follow-up question Undefined behavior and sequence points reloaded.

(Note: This is meant to be an entry to Stack Overflow's C++ FAQ. If you want to critique the idea of providing an FAQ in this form, then the posting on meta that started all this would be the place to do that. Answers to that question are monitored in the C++ chatroom, where the FAQ idea started out in the first place, so your answer is very likely to get read by those who came up with the idea.)

Undefined behavior and sequence points, The expressions' evaluation is unsequenced. The execution of unsequenced evaluations can overlap, with catastrophic undefined behavior if they share state. If you've read this, be sure to visit the follow-up question Undefined behavior and sequence points reloaded. (Note: This is meant to be an entry to Stack Overflow's C++ FAQ. If you want to critique the idea of providing an FAQ in this form, then the posting on meta that started all this would be the place to do that.

Sequence point, The analyzer detected an expression leading to undefined behavior. A variable is used several times between two sequence points while its  More about undefined behavior (and its two more and less dangerous brothers, undefined behavior and implementation-defined behavior) can be found in this stackoverflow post. The problem is related to another notion as well. That of sequence points. There is a great description of sequence points in C and C++ in this stackoverflow answer. The Standard states

C++17 (N4659) includes a proposal Refining Expression Evaluation Order for Idiomatic C++ which defines a stricter order of expression evaluation.

In particular, the following sentence was added:

8.18 Assignment and compound assignment operators:....

In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression. The right operand is sequenced before the left operand.

It makes several cases of previously undefined behavior valid, including the one in question:

a[++i] = i;

However several other similar cases still lead to undefined behavior.

In N4140:

i = i++ + 1; // the behavior is undefined

But in N4659

i = i++ + 1; // the value of i is incremented
i = i++ + i; // the behavior is undefined

Of course, using a C++17 compliant compiler does not necessarily mean that one should start writing such expressions.

V567. The modification of a variable is unsequenced relative to , in a computer program's execution at which it is guaranteed that all side effects of previous evaluations will have been performed, and no side effects from subsequent evaluations have yet been performed. Adding more sequence points is sometimes necessary to make an expression defined and to ensure a single valid order of evaluation. Places in which sequence points occur: Between evaluation of the left and right operands of the &&, ||, and comma operators.

I am guessing there is a fundamental reason for the change, it isn't merely cosmetic to make the old interpretation clearer: that reason is concurrency. Unspecified order of elaboration is merely selection of one of several possible serial orderings, this is quite different to before and after orderings, because if there is no specified ordering, concurrent evaluation is possible: not so with the old rules. For example in:

f (a,b)

previously either a then b, or, b then a. Now, a and b can be evaluated with instructions interleaved or even on different cores.

sequence points in c, In which direction does the assignment operation takes place in C++? undefined behavior - there are no restrictions on the behavior of the program. Examples of undefined behavior are memory accesses outside of array bounds, signed integer overflow, null pointer dereference, modification of the same scalar more than once in an expression without sequence points, access to an object through a pointer

In C99(ISO/IEC 9899:TC3) which seems absent from this discussion thus far the following steteents are made regarding order of evaluaiton.

[...]the order of evaluation of subexpressions and the order in which side effects take place are both unspecified. (Section 6.5 pp 67)

The order of evaluation of the operands is unspecified. If an attempt is made to modify the result of an assignment operator or to access it after the next sequence point, the behavior[sic] is undefined.(Section 6.5.16 pp 91)

Sequence points, , and never the other way: a = b; This statement assigns to variable a (the lvalue) the value contained in variable b (the rvalue). A variable is used several times between two sequence points while its value is changing. We cannot predict the result of such an expression. Let's consider the notions "undefined behavior" and "sequence point" in detail. Undefined behavior is a feature of some programming languages — most famously C/C++.

Operator precedence and order of evaluation, Unspecified (or undefined) behavior & sequence points. Assume the following code snippet of test.cpp. Our goal was to read integers from stdin and map them  The definition of a particular language might specify one of the possible behaviors or simply say the behavior is undefined. In C, evaluating such an expression yields undefined behavior. In C, sequence points occur in the following places.

Operators - C++ Tutorials, The reason for undefined behavior in PROGRAM 1 is, the operator '+' doesn't have standard defined order of evaluation for its operands. Either f1() or f2() may​  The subexpression i++ causes a side effect, it modifies i’s value, which leads to undefined behavior since i is also referenced elsewhere in the same expression. Unlike above cases, at certain specified points in the execution sequence called sequence points , all side effects of previous evaluations are guaranteed to be complete .

Unspecified (or undefined) behavior & sequence points in C++ , What are “sequence points”? What is the relation between undefined behaviour and sequence points? I often use funny and convoluted  Sequence point. A sequence point defines any point in a computer program's execution at which it is guaranteed that all side effects of previous evaluations will have been performed, and no side effects from subsequent evaluations have yet been performed.

Comments
  • *p++ = 4 isn't Undefined Behaviour . *p++ is interpreted as *(p++). p++ returns p(a copy) and the value in stored at the previous address. Why would that invoke UB? It is perfectly fine.
  • @Mike: AFAIK, there are no (legal) copies of the C++ Standard you could link to.
  • Well, then you could have a link to the ISO's relevant order page. Anyway, thinking about it, the phrase "elementary knowledge of C++ Standard" seems a bit of a contradiction in terms, since if you're reading the standard, you're past the elementary level. Maybe we could list what things in the language you need a basic understanding of, like expression syntax, order of operations, and maybe operator overloading?
  • I'm not sure quoting the standard is the best way to teach newbies
  • @Adrian The first expression invokes an UB because there is no sequence point between the last ++i and the assignement to i. The second expression does not invoke UB because expression i does not change the value of i. In the second example the i++ is followed by a sequence point (,) before the assignment operator is called.
  • Instead of "asymmetric", sequenced before / after are "antisymmetric" relations. This should be changed in the text to conform to the definition of a partial order given later (which also agrees with Wikipedia).
  • Why is 7) item in the last example an UB? Maybe it should be f(i = -1, i = 1)?
  • I fixed the description of the "sequenced before" relation. It is a strict partial order. Obviously, an expression cannot be sequenced before itself, so the relation cannot be reflexive. Hence it is asymmetric not anti-symmetric.
  • 5) being well befined blew my mind off. the explanation by Johannes Schaub wasn't entirely straightforward to get. Especially because I believed that even in ++i (being value evaluated before the + operator that is using it), the standard still doesn't say that its side effect must be finished. But in fact, because it returns an ref to a lvalue which is i itself, it MUST have finished the side effect since the evaluation must be finished, therefore the value must be up to date. This was the crazy part to get in fact.
  • "The ISO C++ Committee members thought that Sequence Points stuffs were quite difficult to understand. So they decided to replace it with the above mentioned relations just for more clear wording and enhanced preciseness." - have you got a reference for that claim? It seems to me that the new relations are harder to understand.
  • I believe, though, that if either 'a' or 'b' includes a function call, they are indeterminately sequenced rather than unsequenced, which is to say that all side-effects from one are required to occur before any side-effects from the other, although the compiler need not be consistent about which one goes first. If that is no longer true, it would break a lot of code which relies upon the operations not overlapping (e.g. if 'a' and 'b' each set up, use, and take down, a shared static state).
  • The question is tagged C++ and not C, which is good because the behaviour in C++17 is quite different from the behaviour in older versions — and bears no relation to the behaviour in C11, C99, C90, etc. Or bears very little relation to it. On the whole, I'd suggest removing this. More significantly, we need to find the equivalent Q&A for C and make sure it is OK (and notes that C++17, in particular, changes the rules — the behaviour in C++11 and before was more or less the same as in C11, though the verbiage describing it in C still uses 'sequence points' whereas C++11 and later does not.