Assignment of a parenthesized expression - c

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.

Related

Value Assignment in 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.

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 operator and side effects with sequence points

I'm looking for some clarification for the emphasised line.
(C99 6.5.16/3) An assignment operator stores a value in the object
designated by the left operand. An assignment expression has the value
of the left operand after the assignment, but is not an lvalue. The
type of an assignment expression is the type of the left operand
unless the left operand has qualified type, in which case it is the
unqualified version of the type of the left operand. The side effect
of updating the stored value of the left operand shall occur between
the previous and the next sequence point.
Consider the following example:
int x = 42;
int y = 0;
int main()
{
// side effect of modifying 'x'
x = y;
}
What are the previous and next sequence point? Is there a sequence point at the start of main?
C99 5.1.2.3 defines sequence points as the places by which all side effects of the previous evaluations have taken place and the side effect of subsequent evaluations have not yet started taking place. The annex C of the standard defines the places where the sequence points take place: function calls, end of logical operators, the comma operator, and the ternary operator, end of a full declarations, end of a full expression, and so on.
In this case, the previous sequence point is the start of main(), and the next sequence point is the semicolon at the end of the assignment. At the first sequence point, x will have a value of 42, and at the second one, it will be 0.
Here is an explanation about sequence points from the C FAQ.
In this case, the sequence points are just before and after the full expression x = y;.
Just to add to user4815162342's answer, too long for a comment. Statements are sequenced:
A statement specifies an action to be performed. Except as indicated,
statements are executed in sequence.
So as a rule of thumb you have a sequence point at every ;, though they are not mentioned explicitly as such in the standard.

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.

About use of parentheses in C

void main()
int a,b,c;
c=(a,b)
This gives c=b while
c=a,b
gives c=a.
What is the reason for the above two?
In this line:
c=(a,b)
The parentheses mean, "evaluate the expression a,b first, then assign the value to c." In this case, b is assigned, because it's the right-hand-side expression of a,b. In C, comma expressions are evaluated left-to-right, with the overall value being that of the rightmost expression.
While in this line:
c=a,b
The assignment is evaluated as the entire left hand side first, which is c=a. This is because the equal = operator takes precedence over the comma , operator. Thus, b doesn't get assigned to c at all. It is equivalent to:
(c=a),b
In C, the comma operator evaluates the first operand, then discard it and then evaluates the right operand. So the outcome is the right operand. And it has the lowest precedence.
c = (a,b)
() has higher precedence than, so a,b evaluates first. The result is b. So c = b.
But when used c = a,b assignment = have higher precedence. So c = a evaluates first. Thus a is assigned to c.
Check this for further details.

Resources