Value Assignment in C - c

I came across this question and expected it to show up as a compile time error but to my surprise each statement separated by comma is executed and the final value is assigned to the variable.
int a,b=5;
a=(b++,++b,b*4,b-3);
printf("%d",a);
Output is 4
This output is exactly what should be the printed when each of those comma separated statements are executed separately. What I am not understanding is how and why does C allow this and how does compiler process this.

See What does the comma operator , do?
After understanding how the comma operator works, we can tell that this code is equivalent to:
int a,b=5;
b++;
++b;
b*4; // nonsense, the result isn't stored anywhere
a=b-3;
printf("%d",a);
5 + 1 + 1 - 3 = 4. The b*4 part does nothing and is just obfuscation.

comma acts both as a separator (in declaration of variables) and operator (evaluation of expressions).
In this case, comma acts as an operator. The comma operator introduces a sequence point between expressions.
The left operand of a comma operator is evaluated as a void expression; there is a sequence point between its evaluation and that of the right operand. Then the right operand is evaluated; the result has its type and value.
So your code is:
a = (b++, ++b, b*4, b-3);
Which is as if you had written this:
a = (5, 7, 28, 4);
So a is 4.

Related

In C, why expression(Statement) containing comma(,) operator work differently

I have a simple C code and big confusion about expressions containing comma(,) operator(s).
int main(){
int i=0,j=11,c;
c=i=j,++i;
printf("c=%d i=%d\n",c,i);
c=(i=j,++i);
printf("c=%d i=%d\n",c,i);
return 0;
}
The above code prints:
c=11 i=12
c=12 i=12
My questions are:
What is the actual work of comma(,) as an operator?
++ has more precedence than , and =, why evaluation is done for the expression on left of comma?
What will be the order if an expression contains operators with different priority, will it depend on comma(,)?
Is it behaving like a substitute of semicolon(;)?
The assignment operator has a higher priority then the comma operator.
Thus expression
c = i = j, ++i;
is equivalent to
( c = i = j ), ++i;
According to the C Standard (6.5.17 Comma operator)
2 The left operand of a comma operator is evaluated as a void
expression; there is a sequence point between its evaluation and that
of the right operand. Then the right operand is evaluated; the result
has its type and value.114)
In the expression above the result of the comma operator is discarded but it has a side effect of increasing i.
In this expression
c = ( i = j, ++i );
due to using parentheses you changed the order of the evaluation of the above expression. Now it is equivalent to
c = ( ( i = j ), ++i );
and variable c gets the value of expression ++i according to the quote from the C Standard listed above.
operator comma is to execute many statement and return only result of last statement.
So for c=i=j,++i; : c=i=j is executed, then ++i and after that result of ++i is returned (but not used).
And for c=(i=j,++i);, according to operator precedence, i=j is executed, and just after ++i is executed, and then affectation to c of result of (i=j, ++i), which is the result of last statement, i.e. ++i
So, the behavior of comma is not really same as semicolon. You can use it as a substitute like in c=i=j,++i;.
Personally, I do not encourage to use this operator, which generates less readable and less maintainable code
What is the actual work of comma(,) as an operator?
The comma operator is mainly a superfluous feature. See this for a description of how it works.
++ has more precedence than , and =, why evaluation is done for the expression on left of comma?
What will be the order if an expression contains operators with different priority, will it depend on comma(,)?
The left operand is evaluated for side effects. The result of the comma operator is the result of the evaluated right operand. Note that the comma operator has the lowest precedence of all operators in C.
Is it behaving like a substitute of semicolon(;)?
Kind of, yeah. Both a semi-colon and the comma operator includes a sequence point. The difference is that the comma operator isn't the end of a statement, so it can be squeezed in with other operators on the same line, and it also returns a result.
There is really no reason why you ever would want to do this though. The main use of the comma operator is to obfuscate code, it should be avoided. The only reason why you need to learn how it works, is because you might encounter crap code containing it.
For example, your nonsense code should be rewritten into something more readable and safe:
int main(){
int i=0;
int j=11;
int c;
i=j;
c=j;
i++;
printf("c=%d i=%d\n",c,i);
i=j;
i++;
c=i;
printf("c=%d i=%d\n",c,i);
return 0;
}
Well let's split it. In the first case c and i take the value of j => c=i=j=11; then you increment i => i=12; So the code is equivalent to this
c = j;
i = j;
++i;
For the second case i takes the value of j => i=j=11 and then you increment i => i=12 and then c takes the value of i => c = 12;
So the code is equivalent to this:
i = j;
++i;
c = i;
The comma operator will evaluate and discard all operations, up to, but not including, the final operation. This allows any number of non-consequential operations to be invoked together on a single line where only the last operation is of interest.
Think of it this way, if you have a number of loop variables to increment at any one location in a loop, you can separate all the additions/subtraction, etc.. over their own individual variables on separate line, but why? Where they are executed (within reason) is of no-consequence to the operation of the code. They then can be invoked on a single line with no adverse effect to the code.

On Dev C++ compiler the output of the following code is 10,10 I am not able to understand how the value of a is assigned to b?

#include<stdio.h>
int main()
{
int a=10,b=20;
a,b=(b,a);
printf("%d, %d ",a,b);
return 0;
}
Output of the following code on dev cpp is 10, 10 I am not getting why?
The comma operator separates expressions in a way similar to how the semicolon separates statements. The value of a comma expression is the same as the value of the last expression in the chain.
Your code snippet has two comma operators - one on the left and one on the right side of the assignment operator. The right side selects the value to be assigned - the last one in the chain, i.e. a. Since comma has lowest priority, assignment is parsed done to variable b, i.e. the assignment is equivalent to
b = a;
Expression a on the left side of the assignment operator has no effect, because it reads the value of a without making any changes to it.
The comma operator works like that. Your statements are:
a // no op
b = (b, // no op
a)
and the value of (b,a) is the value of the last expression in the sequence of comma separated expressions, i.e. a, which is equal to 10.
Try this also:
printf("%d\n", (3,7));

Assigning multiple integers separated by comma to an int in C - Why does that work? What for? [duplicate]

This question already has answers here:
C comma operator
(4 answers)
What does the comma operator , do?
(8 answers)
Closed 7 years ago.
I saw this in an exam and when I tried it out I was surprised. I tried it online and it works too. So I think it is the C language.
Why is that working? What is the use case for such an assignment syntax?
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
int i = (1,2,3,4,5);
printf("%d", i);
return 0;
}
These are not "multiple integers", but a comma operator. The whole parenthesised part is a single expression with each sub-expression (separated by commas) evaluated strictly from left to right. The results of all but the rightmost subexpression are ignored. The result of the whole expression is that of the last (rightmost) expression. Here it is the integer value 5.
Note that this operator is mostly used where only a single expression is allowed to add further side-effects. E.g. in a loop like:
int cnt = 0;
for ( const char *cp = "Hello" ; *cp != '\0' ; cp++, cnt++ ) ;
This counts the number of characters in a C-string, incrementing the pointer and cnt after each iteration. The results are ignored here.
So, this is in no way related to tuples or similar like in Python. There are actually no cases the usage of this operator is unavoidable and it should be used with caution — and some coding standards forbid its usage.
That's the comma operator at work. It evaluates the expression on its left-hand side, creates a sequence point, discards the value of the expression, then evaluates the expression on the right-hand side, and returns that as the value. When there are multiple expressions as in the example, then each is evaluated in turn and only the last is kept. With the sample, the compiler does the evaluation because every value is known at compile time. Note that the argument list to a function is not a use of the comma operator.
That isn't a valid use-case for the comma operator. What might be a more nearly valid use-case would be some operations with side-effects (such as function calls) that need to be sequenced and the final value assigned:
int i = (getchar(), getchar(), getchar());
This sets i to the third character in standard input, or EOF if there are not three characters left in the standard input to be read. Still not a realistic use-case, but better than assigning a list of constants.
In addition to the other answers, you need to watch for instances where a , is the comma operator as opposed to when it is a separator. For example, the following is invalid:
int i = 1,2,3,4,5;
In this case, the , is a separator between variable declarations. It declares i as an int and initializes it to 1, then it attempts to parse 2 as a variable name, which fails.
It works because you're using the "comma operator", which evaluates the subexpressions on the left and right, and has the value from the right-hand expression.
So in (1,2,3,4,5), 1 is evaluated and the result is discarded, then 2,3,4,5... in which (because of the next comma) 2 is evaluated and the result discarded, then 3,4,5... in which 3 is evaluated and discarded, then 4,5... in which 4 is evaluated and discarded, then 5 which becomes the result of the expression.
As for when it's useful, mainly as a shortcut when you need to evaluate several (sub)expressions for their side effects but aren't interested in their values (except maybe the last one). It's sometimes convenient in for loop expressions, such as when incrementing two variables:
for (i=0,j=1; j < len; i++,j++) {
..where it appears in both the initialization expression and the loop expression.
Why is that working?
Because its a valid C syntax. The comma in (1,2,3,4,5) are comma operator
C11: 6.5.17 Comma operator
Syntax
1 expression:
assignment-expression
expression , assignment-expression
Semantics
2 The left operand of a comma operator is evaluated as a void expression; there is a sequence point between its evaluation and that of the right operand. Then the right operand is evaluated; the result has its type and value.114)
What is the use case for such an assignment syntax?
See the example below
3 EXAMPLE As indicated by the syntax, the comma operator (as described in this subclause) cannot appear in contexts where a comma is used to separate items in a list (such as arguments to functions or lists of initializers). On the other hand, it can be used within a parenthesized expression or within the second
expression of a conditional operator in such contexts. In the function call
f(a, (t=3, t+2), c)
the function has three arguments, the second of which has the value 5.

Assignment of a parenthesized expression

Consider the following snippet:
int a, b, c;
a = (b = 3, c = 4, 5, 6);
It turns out that, after those lines are executed, b has the value 3, c has the value 4. Nothing unexpected so far. But a has value 6. Why is that?
Also, does this have an useful use?
Because the , operator discards all the operands to the left, and since 6 is the rightmost operand, it's the only one which is not discarded.
This is from § 6.5.17 n1570 draft
The left operand of a comma operator is evaluated as a void expression; there is a
sequence point between its evaluation and that of the right operand. Then the right
operand is evaluated; the result has its type and value.
EXAMPLE As indicated by the syntax, the comma operator (as described in this subclause) cannot
appear in contexts where a comma is used to separate items in a list (such as arguments to functions or lists
of initializers). On the other hand, it can be used within a parenthesized expression or within the second
expression of a conditional operator in such contexts. In the function call
f(a, (t=3, t+2), c)
the function has three arguments, the second of which has the value 5.
You can read more here
Whenever you use a separator (i.e. ',') in an assignment statement, it assigns a value that is in the last. For example
int i = (2,3);
// i = 3;
variable i get the value of 3 not 2.

Variable definition in C

What does following declaration mean in C?
char a = (10,23,21);
While printing the value of "a" with "%u" the output is 21.
gcc is not giving any error.
What's this kinda declaration and what's the use of it?
You are seeing the comma operator at work. The comma operator a,b evaluates a, throws away the result, then returns b.
Since 10 and 23 have no side effects, this is equivalent to char a = 21;
This is a use of the scalar comma operator. The comma operator evaluates each expression on the left side and throws away the return value, finally returning the rightmost value.
In this case, it's useless; however, if you use it with expressions with side-effects, then it has a real effect.
Example of a semi-"useful" expression (with side-effects):
int a = 10;
int is_a_odd_after_increment = ++a, a % 2;
The first expression (++a) has a clear side-effect, and it is evaluated first (before the a % 2). The second expression is the expression that is yielded into the assignment.

Resources