Consider two functions f() and g(). In C and C++, the + operator is not associated with a sequence point, and therefore in the expression f()+g() it is possible that either f() or g() will be executed first. The comma operator introduces a sequence point, and therefore in the code f(),g() the order of evaluation is defined: first f() is called, and then g() is called.
Sequence points also come into play when the same variable is modified more than once within a single expression. An often-cited example is the C expression i=i++, which apparently both assigns i its previous value and increments i. The final value of i is ambiguous, because, depending on the order of expression evaluation, the increment may occur before, after, or interleaved with the assignment. The definition of a particular language might specify one of the possible behaviors or simply say the behavior is undefined. In C and C++, evaluating such an expression yields undefined behavior.4 Other languages, such as C#, define the precedence of the assignment and increment operator in such a way that the result of the expression i=i++ is guaranteed.
In C5 and C++,6 sequence points occur in the following places. (In C++, overloaded operators act like functions, and thus operators that have been overloaded introduce sequence points in the same way as function calls.)
Partially because of the introduction of language support for threads, C11 and C++11 introduced new terminology for evaluation order. An operation may be "sequenced before" another, or the two can be "indeterminately" sequenced (one must complete before the other) or "unsequenced" (the operations in each expression may be interleaved).
C++17 restricted several aspects of evaluation order. The new expression will always perform the memory allocation before evaluating the constructor arguments. The operators <<, >>, ., .*, ->*, and the subscript and function call operator are guaranteed to be evaluated left to right (whether they are overloaded or not). For example, the code
is newly guaranteed to call a, b and c in that order. The right-hand side of any assignment-like operator is evaluated before the left-hand side, so that b() *= a(); is guaranteed to evaluate a first. Finally, although the order in which function parameters are evaluated remains implementation-defined, the compiler is no longer allowed to interleave sub-expressions across multiple parameters.9
"ISO/IEC 14882:2011". Retrieved 2012-07-04. http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=50372 ↩
"A finer-grained alternative to sequence points (revised) (WG21/N2239 J16/07-0099)". Retrieved 2012-07-05. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2239.html ↩
"Order of evaluation". Retrieved 2015-10-14. http://en.cppreference.com/w/c/language/eval_order ↩
Clause 6.5#2 of the C99 specification: "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." /wiki/C99 ↩
Annex C of the C99 specification lists the circumstances under which a sequence point may be assumed. /wiki/C99 ↩
The 1998 C++ standard lists sequence points for that language in section 1.9, paragraphs 16–18. ↩
C++ standard, ISO 14882:2003, section 1.9, footnote 11. ↩
C++ standard, ISO 14882:2003, section 8.3: "Each init-declarator in a declaration is analyzed separately as if it was in a declaration by itself." ↩
Dos Reis, Gabriel; Sutter, Herb; Caves, Jonathan (2016-06-23). "Refining Expression Evaluation Order for Idiomatic C++" (PDF). open-std.org. pp. 1–5. Retrieved 28 April 2023. https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0145r3.pdf ↩