Reputation: 137
I was reading C Programming Language and found this sentence:
The commas that separate ... variables in declarations ... are not comma operators, and do not guarantee left to right evaluation.
If so, are they comma operators in this code?
int a=1, b=a+1, c=b+a+1, d=c+b+a+1;
I'm pretty sure that it will work. But if they're not comma operators and left to right sequence isn't guaranteed, then the above statement may fail, right?
Upvotes: 10
Views: 3313
Reputation: 222382
The initializers in int a=1, b=a+1, c=b+a+1, d=c+b+a+1;
are sequenced in the order they appear because C 2018 (and C 2011) §6.8 ¶3 says:
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 it is used for b
, a
and b
have values when used for c
, and so on.
§6.8 ¶3 is a bit lacking for two reasons:
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.
Upvotes: 1
Reputation: 753605
The comma in declarations is not a comma operator as found in expressions (declarations are not expressions, though initializations within a declaration are expressions). The quote in the question is accurate when it says the commas that separate declarations are not comma operators.
However, each declarator is complete at the comma or semicolon that follows it, so the variable definitions in the question are fully defined behaviour. The quote is incorrect when it implies that the left-to-right evaluation is not guaranteed — though it is a delicate piece of language dissection. If the commas were comma operators, then that fact would guarantee left-to-right evaluation; since they are not comma operators, then the left-to-right guarantee does not arise from the definition of the comma operator. However, because there are sequence points after each declarator, so the left-to-right valuation is separately guaranteed.
Finding the right wording in the standard to justify that claim is harder than I expected. It is actually in the section on declarators.
§6.7 Declarations
Syntax
declaration:
declaration-specifiers init-declarator-listopt ;
……
init-declarator-list:
init-declarator
init-declarator-list , init-declaratorinit-declarator:
declarator
declarator = initializer¶6 The declaration specifiers consist of a sequence of specifiers that indicate the linkage, storage duration, and part of the type of the entities that the declarators denote. The init-declarator-list is a comma-separated sequence of declarators, each of which may have additional type information, or an initializer, or both. The declarators contain the identifiers (if any) being declared.
¶7 If an identifier for an object is declared with no linkage, the type for the object shall be complete by the end of its declarator, or by the end of its init-declarator if it has an initializer; in the case of function parameters (including in prototypes), it is the adjusted type (see 6.7.6.3) that is required to be complete.
§6.7.6 Declarators
¶3 A full declarator is a declarator that is not part of another declarator. The end of a full declarator is a sequence point.
AFAICS, §6.7.9 Initializers does not add anything relevant.
The sequence point is crucial; it means that everything to the left is fully evaluated and side-effects are complete before continuing; it implies left-to-right sequencing, so the initialization in the question is fully defined.
It is slightly odd that the sequence point is after the full declarator and not the initializer; I don't think that it is significant, though.
Upvotes: 14
Reputation: 7
No, it may not, because in declarations comma acts as a sequence point, guaranteeing that evaluations will be performed in mentioned sequence. You can find more info here: Sequence point
Upvotes: -1