5

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?

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
Mahesha999
  • 22,693
  • 29
  • 116
  • 189
  • 4
    @Mahesha999 actually _bigger_ question would be: why on earth you need to write something like that? Grammar says _"declaration \ declaration-specifiers ; \ declaration-specifiers init-declarator-list ;"_, that's all. What do you think it's intuitive (if there is anything _intuitive_ in the comma operator) to write such code? – Adriano Repetti Oct 22 '14 at 10:55
  • @DebasishJana this does not explain why the declaration case does not work as I explain in my answer which no one else seems to have gotten either. – Shafik Yaghmour Oct 22 '14 at 12:08
  • @AdrianoRepetti the distinction between `,` in an expression and in a declaration seems have been lost in the answers here which I why I added an answer. That is the interesting part of the question. – Shafik Yaghmour Oct 22 '14 at 12:10
  • @DebasishJana the conanical C question for how the comma operator works is [What does the comma operator `,` do in C?](http://stackoverflow.com/q/52550/1708801) you linked to a C++ question. – Shafik Yaghmour Oct 22 '14 at 12:11

3 Answers3

9
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); 
Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • 1
    and it does work with assignment!!! but why??? whats exact specs behind where comma will be allowed or whats allow and not allowed with assignment and initialization? – Mahesha999 Oct 22 '14 at 10:51
  • what it does in fact is assign to `i` the result of `(0,1,2)`, which is, like `operator,(operator,(0,1),2)` – qdii Oct 22 '14 at 10:52
  • @zch even in `int i=(0,1,2)`? – qdii Oct 22 '14 at 10:54
  • @qdii, no, I thought you talk about `i = 0,1,2`. – zch Oct 22 '14 at 10:55
  • @zch: all my fault, I used the word "assign" when I should have written "initialized with". – qdii Oct 22 '14 at 10:57
7

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.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • +1 I still don't see the point of the question but for sure this answers explaining reasons behind that. – Adriano Repetti Oct 22 '14 at 12:12
  • @AdrianoRepetti from what I understand the OP is trying to get why what looks like the same syntax does not work in what seems like similar contexts. If you poke around C or C++ long enough you will find a lot of these oddities that don't have obvious answers. – Shafik Yaghmour Oct 22 '14 at 12:37
  • well thats precise & I feel all such questions can best explained with relevant formal grammar specification from the standard. This gives sort of confidence in language behavior. For above, in short, when compiler encounters *declaration* `int...,...` it interpretes `,` as separator and expects *declarators and (optionally) initializers* to surround comma. It found `1` and `2` which are expressions. So it gave error. When compiler encounters *expression*, it interpretes `,` as operator... – Mahesha999 Oct 22 '14 at 15:12
  • ...What I didnt get is: *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**.[...]* – Mahesha999 Oct 22 '14 at 15:12
  • @Mahesha999 a void expression is an expression that has type *void* which means its evaluation has limited use except for side effects such as a function which does some other work. It is like casting to *void*. It is covered in section `6.3.2.2`. – Shafik Yaghmour Oct 22 '14 at 15:20
  • @Mahesha999 lets says you have `1.0, 2` the operands are double and int the result(*value*) of the comma operator is `2` and the result type is *int*. If on the other hand you had `2, 1.0` the value would be `2.0` and the type would be double. – Shafik Yaghmour Oct 22 '14 at 15:24
  • The comma operator can be used in a declaration: `int i = (0, 1, 2);` – M.M Oct 24 '14 at 04:08
  • @MattMcNabb thank you, I knew I forgot to clarify something, that is now fixed. I meant to clarify that you can not get to a bare `,` but yes you can definitely have a comma operator in `()`. – Shafik Yaghmour Oct 24 '14 at 09:25
  • @MattMcNabb well I do say *basic idea* and in the following paragraph I do say it is a *syntax error* and I think I do a decent job of explaining grammatically why this is the case. One could say I am using *weasal wording* here but I think I provide enough context for those interested to see the distinction. – Shafik Yaghmour Jul 29 '15 at 12:22
  • @ShafikYaghmour fair enough. I dont think I could say it any better – M.M Jul 29 '15 at 12:27
0

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

Arjun Mathew Dan
  • 5,240
  • 1
  • 16
  • 27