When I execute the following code
#include <iostream>
int & f(int &i)
{
puts("this is f");
return ++i;
}
int main()
{
int x = 5;
printf("%d", f(x) = f(x) + 1);
return 0;
}
I get output as 8. I am unable to understand how that's happening. Can anyone give me a reason for that?
It's unspecified which of the two calls to f(x) occurs first; and if the right-hand-side one was called first, it's unspecified whether the prvalue conversion of that occurs before or after the call to the left-hand-side's f(x). But all of those happen before the assignment.
One valid order is:
lhs f(x)
rhs f(x)
rvalue conversion
which results in i = 7 + 1;.
Alternatively it could be:
rhs f(x)
rvalue conversion
lhs f(x)
which results in i = 6 + 1;
There is no undefined behaviour relating to the ++ operator, because there is a sequence-point before and after each function call.
Refs:
[intro.execution]#15
Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced
[expr.ass]#1
In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression.
In this quote, "the value computation of the assignment expression" means the value that this expression takes if it's a sub-expression of a larger expression, e.g. bar = ( foo(x) = foo(x) + 1 );
This code will let you inspect which order your compiler is using. I have inserted bar which passes its value through unmodified.
#include <cstdio>
using namespace std;
int & f(int idx, int &i)
{
printf("this is f %s\n", idx ? "right" : "left");
return ++i;
}
int bar(int idx, int z)
{
printf("bar%d = %d\n", idx, z);
return z;
}
int main()
{
int x=5;
f(0,x)= bar(0, bar(1, f(1,x)) + 1 );
printf("final = %d\n",x);
return 0;
}
Output for my system:
this is f left
this is f right
bar1 = 7
bar0 = 8
final = 8
Output for Coliru:
this is f right
bar1 = 6
bar0 = 7
this is f left
final = 7
Look how this line of code is evaluated:
printf("%d",f(x)=f(x)+1);
Step 1:
Initialization of x
--> x == 5
Step 2:
First call of f (right side of equals sign)
--> x == 6
Step 3:
Adding 1
--> x == 7
Step 4:
Second call of f (left side of equals sign)
--> x == 8
EDIT(see comment for deeper insight & thx to Matt):
You use reference parameter. When you modify the variable x in the f function, you modify too in main function.
First x = 5
When you call f first time, x = 6
When you call f second time, x = 7
Finally, 7 + 1 = 8
Function parameter i is a reference to int x.
So, ++i is actually incrementing x.
f(x) is called twice with initial x=5 which will make x equal to 7.
But 1 is added at printf, making final value printed 8.
#include <iostream>
int & f(int &i)
{
puts("this is f");
return ++i;
}
int main()
{
int x=5;
//f(x)=f(x)+1 equals to following
int& tmp_x = f(x); //x=6
int tmp = f(x)+1; //x = 7, tmp = 8
tmp_x = tmp; //x=8
printf("%d",tmp_x);
return 0;
}
Related
I am not able to understand, why the output of the code is not what I was expecting.
#include <iostream>
using namespace std;
int main()
{
int m = 2, n = 6;
int &x = m;
int &y = n;
m = x++;
x = m++;
n = y++;
y = n++;
cout<< m << " " << n;
return 0;
}
I was expecting 4 8
This line:
m = x++;
is equivalent to:
x = x++;
since m is a reference to x.
From c++17, the right hand side is evaluated first, resulting in 2. Then x is incremented to 3. Then the assignment of the right hand side value to the left hand side is done. But this uses the old value of the right hand side, which is 2. So the above statement effectively does nothing.
Before c++17,
m = x++;
is undefined behavior.
Notice how the operators are post-increment and not pre-increment... You're basically doing nothing.
m = x++; means that increment x (i.e. m) but return the old value of x (i.e. m). Assignment takes place after the increment and return of old value and the old value is what ends up getting assigned. So, you end up essentially with a bunch of self-assignments.
int main() {
int y;
int x{ y = 5 };
//x is 5
}
How is this possible, since y = 5 is not a calculable expression?
Also, why doesn't the compiler or IDE complain about main() not returning an int?
How is this possible, since y = 5 is not a calculable expression?
It is an assignment, and assignments yield values, i.e. the "cv-unqualified type of the left operand", see [expr.ass/3]. Hence y = 5 results in y, which is 5, which is used to initialize x.
With respect to your second question, see cppreference on main (or [basic.start.main/5]):
The body of the main function does not need to contain the return statement: if control reaches the end of main without encountering a return statement, the effect is that of executing return 0;.
Hence, compiler or IDE warning you about a missing return statement at the end of main would be plain wrong. Admittedly, the fact that you should always return objects from non-void functions execpt main is kind of... well, for historical reason I guess.
I will start from your last question
Also, why doesn't the compiler or IDE complain about main() not
returning an int?
According to the C++ Standard (6.6.1 main function)
5 A return statement in main has the effect of leaving the main
function (destroying any objects with automatic storage duration) and
calling std::exit with the return value as the argument. If control
flows off the end of the compound-statement of main, the effect is
equivalent to a return with operand 0 (see also 18.3).
And relative to this question
How is this possible, since y = 5 is not a calculable expression?
From the C++ Standard (8.18 Assignment and compound assignment operators)
1 The assignment operator (=) and the compound assignment operators
all group right-to-left. All require a modifiable lvalue as their left
operand and return an lvalue referring to the left operand.
Sp this declaration
int x{ y = 5 };
can be equivalently split into two statements
y = 5;
int x{ y };
Moreover in C++ you can even to make a reference to the variable y the following way
int &x{ y = 5 };
Here is a demonstrative program
#include <iostream>
int main()
{
int y;
int &x{ y = 5 };
std::cout << "y = " << y << '\n';
x = 10;
std::cout << "y = " << y << '\n';
}
Its output is
y = 5
y = 10
You may this declaration
int x{ y = 5 };
rewrite also like
int x = { y = 5 };
However take into account that there is a difference between these (looking similarly as the above declarations) two declarations.
auto x{ y = 5 };
and
auto x = { y = 5 };
In the first declaration the variable x has the type int.
In the second declaration the variable x has the type std::initializer_list<int>.
To make the difference more visible see how the values of the objects are outputted.
#include <iostream>
int main()
{
int y;
auto x1 { y = 5 };
std::cout << "x1 = " << x1 << '\n';
auto x2 = { y = 10 };
std::cout << "*x2.begin()= " << *x2.begin() << '\n';
std::cout << "y = " << y << '\n';
return 0;
}
The program output is
x1 = 5
*x2.begin()= 10
y = 10
The operator=() results in a value, which is the value assigned to the variable. Because of this, it is possible to chain assignments like this:
int x, y, z;
x = y = z = 1;
If you take a look at the documentation on cppreference, you'll see that operator=() return a reference to the object that was assigned. Therefore, a assignment can be used as an expression that returns the object that was assigned.
Then, it's just a normal assignment with braces.
Can someone please explain what is happening in the following code? (Taken from GeeksForGeeks)
int main(){
int a = 10;
++a = 20; // works
printf("a = %d", a);
getchar();
return 0;
}
What exactly is happening when the statement ++a = 20 is executed? Also, please clarify why this code fails in execution?
int main(){
int a = 10;
a++ = 20; // error
printf("a = %d", a);
getchar();
return 0;
}
Code Taken From: http://www.geeksforgeeks.org/g-fact-40/
When you do
++a = 20;
it's roughly equivalent to
a = a + 1;
a = 20;
But when you do
a++ = 20;
it's roughly equivalent to
int temp = a;
a = a + 1;
temp = 20;
But the variable temp doesn't really exist. The result of a++ is something called an rvalue and those can't be assigned to. Rvalues are supposed to be on the right hand side of an assignment, not left hand side. (That's basically what the l and r in lvalue and rvalue comes from.)
See e.g. this values category reference for more information about lvalues and rvalues.
This is the difference between r and l values. If you would have compiled the 2nd code snippet with gcc you would have seen this:
lvalue required as left operand of assignment
meaning, that a++ is rvalue and not a lvalue as it should be if you want to assign something to it
int main(){
int a = 10;
++a = 20; // works
printf("a = %d", a);
getchar();
return 0;
}
This is a c Language.
Explaining Line by line
int main() THIS line define an entry function called main which is expected to return a type integer(int)
int a = 10 declares a variable integer whose value is 10;
++a = 20; AT this point your code is incrementing the value of a by 1 before any operation is performed on a.
This means that, the value of a is incremented by 1 bfore a is assign the value of 20;....
the statement ++a = 20 is incorect in the sense that, a is 10 initially, and you increment it to 11 . Is like saying 11 = 20; this may not throw an error because the code line is not useful.
printf() is a c-method to print file to screen, passing a string "a = %d" tells the compiler to print a to a decimal number(%d).
getchar() is use to terminate the running program and return 0 is to forcefully tell the operating system that the code run successfully and return integer value 0.
int main(){
int a = 10;
a++ = 20; // error
printf("a = %d", a);
getchar();
return 0;
}
This didn't at a++ = 20 because , right value increment perform the operation before it increment unlike ++a who increment before performing operation.
So this isn't possible and it never works because a is already 10, and you are saying the value ++ and assign 20, you can't assign a value to it, it should be the one calculating its own value. So the compiler will want to interprete is as variable a++ = 20, and ++ can not be a vaiable name. That's why it never work.
What is the essence of incrementation and decrementation in c....its useful for creating conditional statement e.g for loop, while statement etc. for example:
for(int i = 0; i < 4; i++)
{
printf('THis is c-language');
}
or
int i = 0;
while(i < 4){
printf('THis is c-Language');
i++;
}
so therefore, following the programming rules and regulations, you are not allow to assign value to either a++ or ++a
they are for the compilers to manipulate, so never assign value to them.
Thank you.
The left operand of the assignment operator should be an lvalue.
The expression ++a is an lvalue while a++ is not and therefore it can't be the left operand of the assignment operator.
n3797-ยง 5.3.3(p1):
[...] The result is the updated operand; it is an lvalue [...]
I've been trying to understand how post and pre increments work lately and I've been over thinking it too much.
Does "Product" become 25 after one iteration?
Product *=5++
And does "Quotient" become 5/6 after one iteration?
Quotient /= ++x
5++ is just incorrect.
Quotient /= ++x; is the same as x = x + 1; Quotient = Quotient / x; (assuming these are just plain numbers).
Your code isn't valid C++, since the built-in post-increment operator may only be applied to lvalues, but literal integers are rvalues.
Beside that, the value of a (built-in) pre-increment expression is the incremented value, while the value of a post-increment expression is the original value.
Pre-increment modifies the variable and evaluates to the modified value.
Post-increment evaluates to the value of the variable and then increments the variable.
int a = 5;
int b = ++a; // a = a + 1; b = a
int c = a++; // c = a; a = a + 1
Consider these simple implementations of ++ for int
int& int::preincrement()
{
this->m_value += 1;
return *this;
}
int int::postincrement()
{
int before = this->m_value;
this->m_value += 1;
return before;
}
I am trying to implement a simple compiler using flex & bison, and got stuck in the postfix notation.
(The compiler should behave like the C++ compiler)
Here is the problem:
Given the following code:
int x = 0;
int y = x++ || x++ ; //y=1 , x = 2 this is understandable
int z = x++ + x++ ; // z = 0 , x=2
the first line is fine because of the following grammar:
expression = expression || expression; // x=0
expression = 0 || expression // x= 1
expression = 0 || 1 //x=2
expression = 1 // x=2
y = 1
However, I don't understand why z=0.
When my bison grammar sees 'variable' ++ it first returns the variables value, and only then increments it by 1. I used to think thats how C++ works, but it won't work for the 'z' variable.
Any advice on how to solve this case?
int z = x++ + x++;
Although z may appear to be 0, it is not, it could in fact be any value and will depend entirely upon the compiler you are using. This is because the assignment of z has undefined behaviour.
The undefined behaviour comes from the value of x being changed more than once between sequence points. In C++, the || operator is a sequence point which is why the assignment of y is working as expected, however the + operator is not a sequence point.
There are of course various other sequence points in C++, the ; being a more prominent example.
I should also point out that the ++ operator returns the previous value of the variable, that is in this example
#include <iostream>
using namespace std;
int main() {
int x = 0;
int y = x++;
cout << y << endl;
return 0;
}
The value printed out for y is 0.
Saying the same thing another way. A C compiler is free to implement
int z = x++ + x++;
as either
z = x + x
incr x
incr x
or as
int r1 = x;
incr x
z = r1 + x
incr x
Your compiler appears to be using the first plan.