Search code examples
clanguage-lawyerdefinitioncomma-operatorsequence-points

Does the comma in a declaration for multiple objects introduce a sequence point like the comma operator?


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?


Solution

  • 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.