Does the definition
int a = 0, b = a++, c = a++;have defined behavior in C?
Yes, because C 2018 6.8 3 says these initializations (not all, see bottom) are evaluated in the order they appear:
… The initializers of objects that have automatic storage duration, and the variable length array declarators of ordinary identifiers with block scope, are evaluated and the values are stored in the objects (including storing an indeterminate value in objects without an initializer) each time the declaration is reached in the order of execution, as if it were a statement, and within each declaration in the order that declarators appear. [Emphasis added.]
Also, 6.8 4 tells us that each initializer is a full expression and there is a sequence point after the evaluation of a full expression and evaluation of the next:
A full expression is an expression that is not part of another expression, nor part of a declarator or abstract declarator. There is also an implicit full expression in which the non-constant size expressions for a variably modified type are evaluated; within that full expression, the evaluation of different size expressions are unsequenced with respect to one another. There is a sequence point between the evaluation of a full expression and the evaluation of the next full expression to be evaluated.
Given both the above, the initializers are sequenced in the order they appear. a is initialized first and so has a value when a++ is evaluated for b, and the side effects for that are completed before the a++ for c begins, so the whole declaration is safe from the “unsequenced effects” rule in 6.5 2.
6.8 3 is a bit lacking for two reasons:
- Initializers are not part of the grammar token declarator (they are part of the init-declarator, a containing token of declarator). However, this seems like a wording issue, and we can take the initializers to be associated with their declarators.
- It does not specify ordering between the expressions in a declarator (such as sizes for variable length arrays) and its initializer(s).
Also note that not all initializers are evaluated in the order they appear in a declaration. 6.7.9 23 discusses initializers for aggregates and unions and says:
The evaluations of the initialization list expressions are indeterminately sequenced with respect to one another and thus the order in which any side effects occur is unspecified.
History
The wording in 6.8 3 quoted above goes back to C 1999. In C 1990, it had this form in 6.6.2, which is about compound statements:
… The initializers of objects that have automatic storage duration are evaluated and the values are stored in the objects in the order their declarators appear in the translation unit.