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
-------------------------------------
CodePudding user response:
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.
CodePudding user response:
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.
- Set
- Evaluate
=
by adding one to the returned reference, settingi: 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.
- Set
- Evaluate left side:
- Set
i: 6->7
. - Return ref to
i
which holds 7 now.
- Set
- Evaluate
=
by assigning the right side(7
) to left side(i
), settingi
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
.