Assignment of two values in parentheses in C - c

What does this piece of code in C do:
p = (1, 2.1);
What do we know about p?

The comma operator in C is a sequence point which means that the expressions separated by the comma are executed from left to right. The value of the whole expression is the value of the rightmost expression, in your case 2.1, which gets assigned to the variable p.
Since the expressions in your example don’t have side effects, the use of the comma separator here makes no sense whatsoever.
The parentheses on the other hand are important since the assignment operator (=) binds stronger than the comma operator (it has higher precedence) and would get evaluated before the comma operator without the parentheses. The result would thus be p == 1.

It's a mistake. the comma operator is similar to ;. It does the one, then the other. so (1,2.1) evaluates to 2.1
p will be 2.1 (or 2, if p is an int and needs to be truncated...)

all comma seprated expressions will be evaluated from left to right and value of rightmost expression will be returned.
so p will 2.1.

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.

Comma-Separated return arguments in C function [duplicate]

This question already has answers here:
What does the comma operator , do?
(8 answers)
Closed 7 years ago.
While completing a C programming test, I was given a question regarding the expected output from a function which seem to return two values. It was structured as follows:
int multi_return_args(void)
{
return (44,66);
}
The question caught me by surprise and inherently thought that if possible the first argument would be passed to the caller.
But after compiling it, the result is 66 instead. After a quick search I couldn't find anything about structuring a return statement like this so was wondering if some could help me.
Why does it behave like this and why?
The comma operator evaluates a series of expressions. The value of the comma group is the value of the last element in the list.
In the example you show the leading constant expression 44 has no effect, but if the expression had a side effect, it would occur. For example,
return printf( "we're done" ), 66;
In this case, the program would print "we're done" and then return 66.
In your code,
return (44,66);
is making (mis)use of the comma operator property. Here, it essentially discards the first (left side) operand of the , operator and returns the value of that of the second one (right operand).
To quote the C11 standard, chapter §6.5.17, Comma operator
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.
In this case, it is same as writing
return 66;
However, FWIW, the left hand side operand is evaluated as a void expression, meaning, if there is any side effect of that evaluation, that will take place as usual, but the result of the whole expression of the statement involving the comma operator will be having the type and the value of the evaluation of the right hand side operand.
This will return 66. There is nothing special about returning (44,66).
(44,66) is an expression that has the value 66 and therefore your function will return 66.
Read more about the comma operator.
Coma operator always returns the value of the rightmost operand when multiple comma operators are used inside an expression.
It will obviously return 66.

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.

(p++)->x Why are the parentheses unnecessary? (K&R)

From page 123 of The C Programming Language by K&R:
(p++)->x increments p after accessing x. (This last set of parentheses is unnecessary. Why?)
Why is it unnecessary considering that -> binds stronger than ++?
EDIT: Contrast the given expression with ++p->x, the latter is evaluated as ++(p->x) which would increment x, not p. So in this case parentheses are necessary and we must write (++p)->x if we want to increment p.
The only other possible interpretation is:
p++(->x)
and that doesn't mean anything. It's not even valid. The only possible way to interpret this in a valid way is (p++)->x.
Exactly because -> binds stronger than ++. (it doesn't, thanks #KerrekSB.)
increments p after accessing x.
So first you access x of p, then you increment p. That perfectly matches the order of evaluation of the -> and the + operators.
Edit: aww, these edit's...
So what happens when you write ++p->x is that it could be interpreted either as ++(p->x) or as (++p)->x (which one is actually chosen is just a matter of language design, K&R thought it would be a good idea to make it evaluate as in the first case). The thing is that this ambiguity doesn't exist in the case of p++->x, since it can only be interpreted as (p++)->x. The other alternatives, p(++->x), p(++->)x and p++(->x) are really just syntactically malformed "expressions".
The maximal munch strategy says that p++->x is divided into the following preprocessing tokens:
p then ++ then -> then x
In p++->x expression there are two operators, the postfix ++ operator and the postifx -> operator. Both operators being postfix operators, they have the same precedence and there is no ambiguity in parsing the expression. p++->x is equivalent to (p++)->x.
For ++p->x expression, the situation is different.
In ++p->x, the ++ is not a postfix operator, it is the ++ unary operator. C gives postfix operators higher precedence over all unary operators and this is why ++p->x is actually equivalent to ++(p->x).
EDIT: I changed the first part of the answer as a result of Steve's comment.
Both post-increment and member access operator are postfix expressions and bind the same. Considering that they apply to the primary or postfix expression to the left, there can't be ambiguity.
In
p++->x
The postfix-++ operator can apply only to the expression to the left of it (i.e. to p).
Similarly ->x can only be an access to the expression to its left, which is p++. Writing that expression as (p++) is not needed, but also does no harm.
The "after" in your description of the effects, does not express temporal order of increment and member access. It only expresses that the result of p++ is the value p had before the increment and that that value is the value used for the member access.
The expresion p++ results in a pointer with the value of p. Later on, the ++ part is performed, but for the purposes of interpreting the expression, it may just as well not be there. ->x makes the compiler add the offset for the member x to the original address in p and access that value.
If you change the statement to :
p->x; p++;
it would do exactly the same thing.
The order of precedence is actually exactly the same, as can be seen here - but it doesn't really matter.

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