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-declarator
init-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.
f(a += b, a)
. – Singlesint a = 1;
int b = a + 1;
int c = b + a + 1;
int d = c + b + a + 1;
[on separate lines]. Most style guides I've read prefer the split line approach too. IMO, using the commas is harder to read/understand [quickly] when looking at a lot of code. To me, the sequential intent is clearer. Others, seeing the commas might have to research this, just like your question is asking. Also note that I added some whitespace as visual aid as well. – Steadfastf(a += b, a)
is a bad coding style as it has been talked a lot not to use likeprintf("%d, %d\n", a++, a++);
and also the result isn't guaranteed by C standard. But I haven't see the same discussion aboutint a = 1, b = a + 1 ...
and that's why I asked this question. – Popelka