So I came across this question somewhere:
Case 1:
int a;
a = 1, 2, 3;
printf("%d", a);
Case 2:
int a = 1, 2, 3;
printf("%d", a);
The explanation says:
The second case gives error because comma is used as a separator, In first case = takes precedence over , so it is basically (a=1), 2, 3;
But I want to ask why does = not take precedence over , in Case 2?
It is not just a question of precedence, but rather a question of the language grammar: the = in both cases is not the same operator:
in the declaration int a = 1, 2, 3;, the = token introduces an initializer which cannot be a comma expression. The , ends the initializer and the compiler issues an error because 2 is not a valid identifier for another variable.
in the statement a = 1, 2, 3;, a = 1, 2, 3 is an expression, parsed as ((a = 1), 2), 3 because = has higher precedence than ,. = is the assignment operator whose right hand side is an expression, this assignment is the left operand of a comma operator , followed by a constant expression 2, a = 1, 2 itself the left operand of the final , operator whose right operand is 3. The statement is equivalent to ((a = 1), 2), 3);, which simplifies into a = 1;.
This
int a = 1, 2, 3;/* not a valid one */
is wrong because since = has higher priority, so it become int a = 1 internally and there is no name for 2 and 3 thats why this statement is not valid and cause compile time error.
To avoid this you might want to use
int a = (1, 2, 3); /* evaluate all expression inside () from L->R and assign right most expression to a i.e a=3*/
And here
int a;
a = 1,2,3;
there are two operator = and , and see man operator. The assignment operator = has higher priority than comma operator. So it becomes a=1.
a = 1,2,3;
| L--->R(coma operator associativity)
this got assigned to a
for e.g
int x = 10, y = 20,z;
z = 100,200,y=30,0; /* solve all expression form L to R, but finally it becomes z=100*/
printf("x = %d y = %d z = %d\n",x,y,z);/* x = 10, y = 30(not 20) z = 100 */
z = (100,200,y=30,0); /* solve all expression form L to R, but assign right most expression value to z*/
Inside variable declarations (as case 1) comma are used to declare several variables, for example:
int a,b=2,c=b+1,d; //here only b and c were initialized
An statement in C/C++ could be a list of comma separated expressions (this is what happens in case 2):
a=b+1, c+=2, b++, d = a+b+c, 3, d; //these are expressions, remember one literal is an expression too!!!
NOTE : comma (,) is a compile time operator,
from my side their is Four cases that you can come across :
case 1
int a = 1, 2, 3; // invalid case cause too many initializers
case 2
int a = (1, 2, 3); // valid case
/* You can expand this line as a :
1;
2;
int a = 3;
*/
case 3
int a;
a = 1, 2, 3; // valid case
/* You can expand this line as a :
a = 1; // expression 1
2; // expression 2
3; // expression 3
*/
case 4
int a;
a = ( 1, 2, 3);// valid case
/* You can expand this line as a :
1; // expression 1
2; // expression 2
a = 3; // expression 3
*/
In above cases in place of 1, 2, 3 we can use any valid expression in C, explore more!!
Related
I don't understand why my two expressions produce the same result even though the second expression calls f() twice.
I am using gcc with C++20 enabled.
#include <iostream>
using namespace std;
int& f(int& i, string name);
int main() {
puts("\n-------------------------------------\n");
int x = 5;
/* expression one */
printf("the result of (f(x) += 1) is:--> %d\n", f(x, "one") += 1);
printf("x is: %d\n",x);
printf("********************\n");
x = 5;
/* expression two */
printf("the result is:--> %d\n", f(x, "two") = f(x, "three") + 1);
printf("x is: %d\n", x);
puts("\n-------------------------------------\n");
return EXIT_SUCCESS;
}
int& f(int& i, string name) {
++i;
printf("<%s> value of i is: %d\n", name.c_str(), i);
return i;
}
The output of my program is:
-------------------------------------
<one> value of i is: 6
the result of (f(x) += 1) is:--> 7
x is: 7
********************
<three> value of i is: 6
<two> value of i is: 7
the result is:--> 7
x is: 7
-------------------------------------
If we break expression 2 into separate steps it might become clearer what is happening:
f(x, "two") = f(x, "three") + 1;
Is equivalent to (though note the order of evaluation isn't guaranteed before c++17):
int b = f(x, "three") + 1;
int& a = f(x, "two");
a = b;
However as f(x) returns a reference to x, a is also a reference to x. Using this if we then expand the function calls we get:
int b = ++x + 1;
++x;
x = b;
Notice how the second ++x is ignored, this is why it doesn't have the value you expect.
Note that this is undefined behaviour before (and correct after) C++17 which explicitly sequences evaluation of left, right sides including their side-effects.
f(x, "one") += 1
is evaluated as:
Evaluate right side to 1.
Evaluate left side:
Set i: 5->6
Return ref to i which holds 6.
Evaluate += by adding one to the returned reference, setting i: 6->7.
The expression is evaluated to ref to i holding 7.
f(x, "two") = f(x, "three") + 1
Evaluate right side:
Set i: 5->6
Return ref to i which holds 6 now.
Add 1 -> right side is 7.
Evaluate left side:
Set i: 6->7.
Return ref to i which holds 7 now.
Evaluate = by assigning the right side(7) to left side(i), setting i to 7.
The expression is evaluated to ref to i holding 7.
In the second expression it doesn't matter what happens to i inside left f call - if it returns i ref, it will be set to 7.
I'm learning c++ and currently learning about operator precedence. I'm playing with the following examples. Imagine each piece as distinct pieces of code run at separate times, not multiple code blocks within the same method.
int b = 4;
int result = ++b;
// In the above example the result will be 5, as expected.
int b = 4;
int result = ++b + b;
// Here the result will be 10 as expected.
int b = 4;
int result = ++b + ++b;
Here the result is 12. I don't understand why. Shouldn't the compiler evaluate ++b changing 4 to 5, then ++b changing 5 to 6, resulting in 5+6 = 11?
It's undefined behaviour, violating sequence rules.
Between the previous and next sequence points a scalar object must have its stored value modified at most once by the evaluation of an expression, otherwise the behavior is undefined.
int b = 4;
int result = ++b + ++b;
I've seen instances where someone would use return statements with multiple values. For example: return 8, 10, 6; As far as I know, only one of these values will actually be returned. What is the benefit of using return this way?
Specifically, this question appears on my homework.
The statement: return 2 * 3 + 1, 1 + 5; returns the value ____.
I know it would always return 6, so why would I ever write it like this?
Forgive me if this is a simple question. I am still somewhat new to programming.
The statement return 2 * 3 + 1, 1 + 5; returns the value 6.
This the trick of comma operator in C++. You can read more about it here:
https://en.cppreference.com/w/cpp/language/operator_other
A comma operator is basically a list of expressions separated by commas, they will be evaluated from left to right, and the result of the last item will be treated as the result of the whole comma operator.
Here is a simple example demonstrating how comma operator works.
int foo() {
int i = 1;
return i += 2, i++, i + 5; // This is a comma operator with three items
// i += 2 will be evaluated first, then i == 3
// i++ will be evaluated second, then i == 4
// i + 5 will be evaluate last, and the result is 9
// the result of the last item is returned by the return statement
}
int main() {
std::cout << foo();
return 0;
}
This code prints 9.
When you do this you are avoiding using math in your function block and this make your function like working 3 time and result would be the one you want
This (note the comma operator):
#include <iostream>
int main() {
int x;
x = 2, 3;
std::cout << x << "\n";
return 0;
}
outputs 2.
However, if you use return with the comma operator, this:
#include <iostream>
int f() { return 2, 3; }
int main() {
int x;
x = f();
std::cout << x << "\n";
return 0;
}
outputs 3.
Why is the comma operator behaving differently with return?
According to the Operator Precedence, comma operator has lower precedence than operator=, so x = 2,3; is equivalent to (x = 2),3;. (Operator precedence determines how operator will be bound to its arguments, tighter or looser than other operators according to their precedences.)
Note the comma expression is (x = 2),3 here, not 2,3. x = 2 is evaluated at first (and its side effects are completed), then the result is discarded, then 3 is evaluated (it does nothing in fact). That's why the value of x is 2. Note that 3 is the result of the whole comma expression (i.e. x = 2,3), it won't be used to assign to x. (Change it to x = (2,3);, x will be assigned with 3.)
For return 2,3;, the comma expression is 2,3, 2 is evaluated then its result is discarded, and then 3 is evaluated and returned as the result of the whole comma expression, which is returned by the return statement later.
Additional informations about Expressions and Statements
An expression is a sequence of operators and their operands, that specifies a computation.
x = 2,3; is expression statement, x = 2,3 is the expression here.
An expression followed by a semicolon is a statement.
Syntax: attr(optional) expression(optional) ; (1)
return 2,3; is jump statement (return statement), 2,3 is the expression here.
Syntax: attr(optional) return expression(optional) ; (1)
The comma (also known as the expression separation) operator is evaluated from left to right. So return 2,3; is equivalent to return 3;.
The evaluation of x = 2,3; is (x = 2), 3; due to operator precedence. Evaluation is still from left to right, and the entire expression has the value 3 with the side-effect of x assuming the value of 2.
This statement:
x = 2,3;
is composed by two expressions:
> x = 2
> 3
Since operator precedence,
= has more precedence than comma ,, so x = 2 is evaluated and after 3. Then x will be equal to 2.
In the return instead:
int f(){ return 2,3; }
The language syntax is :
return <expression>
Note return is not part of expression.
So in that case the two expression will be evaluated will be:
> 2
> 3
But only the second (3) will be returned.
Try to apply the simplistic approach just highlighting the precedence with parenthesis:
( x = 2 ), 3;
return ( 2, 3 );
Now we can see the binary operator "," working in the same way on both, from left to right.
This question already has answers here:
Why is this double initialization with a comma illegal?
(4 answers)
Closed 9 years ago.
Working on GCC compiler, with following two cases of operators in C program, observed different behaviors.
1.
int i = 1,2,3;
printf("%d",i); // this will give compile time error
And,
2.
int i;
i = 1,2,3;
printf("%d",i); // Its output will be 1.
In 1st case compiler gave error "error: expected identifier or ‘(’ before numeric constant".
And in second case, no errors, and output is 1.
Can anybody explain here the compiler behavior in both the cases in detail?
How does compiler interpret both statements?
Thanks in advance for your inputs.
In the first case the comma separates declaration and initialisation of several variables of the same type:
int i = 1, j = 2, k = 3;
You can add parentheses to tell the compiler it's an expression.
int i = (1, 2, 3);
If you combine them, it's easier to see why the comma is ambiguous without parentheses:
int i = (1, 2, 3), j = 4, k = 5;
In the second case the comma separates 3 expressions.
(i = 1), 2, 3