Why does this use of comma work in a expression bu

2019-01-26 13:08发布

问题:

Am from high level OOP languages C# and Java and recently started scratching my head in C. I feel C a bit weird as equally as one feels JS is. So want to clarify below:

Below gives error and that seems intuitive as it looks like incorrect syntax even in OOP languages

int i=0,1,2;  

/*
Error : expected identifier or ‘(’ before numeric constant
 int i = 0, 1, 2;
            ^
*/

However below works surprisingly:

int i;
i = 0,1,2;    //works

Why is this behavior? Is their any significance to keep such behavior or just some parsing technicalities?

回答1:

This is actually a tricky question because it relies on the details of the C grammar which is complicated. The best source for understanding it is the draft standard, we can use Annex A Language syntax summary as a reference.

The basic idea is that:

int i=0,1,2; 

is a declaration and:

i = 0,1,2; 

is an expression.

In an expression we can have the comma operator which evaluates the left hand side(usually for side effects), throws away the result and then evaluates the right hand side etc...

In declaration the comma is a grammatical separator not the comma operator. The , separates declarators and since 1 and 2 are not declarators in the context of a declaration this is incorrect syntax:

 int i=0,1,2;
        ^^^^

The relevant grammar from the C99 standard is as follows:

init-declarator-list:
    init-declarator
    init-declarator-list , init-declarator   <--- here comma is just a seperator
init-declarator:
    declarator
    declarator = initializer

So in this case the , separates init-declarators which can either be a declarator or a declarator = initializer neither 1 nor 2 are declarators and so we have incorrect syntax.

It is worth nothing that an initializer can be an assignment-expression but this expression does not gives us a path to a bare comma operator, although we could end up with a comma operator in ()(through primary-expression) but this would not look like a separator.

For the expression the relevant grammar from section 6.5.17 is:

expression:
    assignment-expression
    expression , assignment-expression

and the description of the comma operator is as follows:

The left operand of a comma operator is evaluated as a void expression; there is a sequence point after its evaluation. Then the right operand is evaluated; the result has its type and value.[...]

Noting that the comma operator has the lowest precedence the following expression:

i = 0,1,2; 

is equivalent to:

(i = 0),1,2; 

and so i will get the value of 0 and the results of the further evaluations are thrown away.



回答2:

i = 0,1,2; 

This is assignment, which is equivalent to:

(i = 0), 1, 2;

The comma operator(which has the lowest precedence) evaluates all operands from left to right, first the assignment i = 0, then the expression 1 and 2 and throws the result away.

The second example

int i=0,1,2;  

is initialization. Compare it with the legal initialization int i = 0, j = 0;.

It works if you use:

int i=(0,1,2); 


回答3:

1.

  int i, j;
  i = 3,0,1,2;
  printf("%d\n", i); => prints 3

2.

  i = 3,j =7;
  printf("%d, %d\n", i, j); => prints 3 and 7

i = 3,0,1,2; This assigns 3 to i, then executes 0, 1 and 2. Check the 2nd example I mentioned.

Also, Try i=3;0;1;2; This will not report any error. It will just execute (i=3), (0), (1) and (2).