Strange post-increment behaviour in C++ [duplicate] - c++

This question already has answers here:
Undefined behavior and sequence points
(5 answers)
Closed 6 years ago.
I have a friend who is getting different output than I do for the following program:
int main() {
int x = 20, y = 35;
x = y++ + x++;
y = ++y + ++x;
printf("%d%d", x, y);
return 0;
}
I am using Ubuntu, and have tried using gcc and clang. I get 5693 from both.
My friend is using Visual Studio 2015, and gets 5794.
The answer I get (5693) makes most sense to me, since:
the first line sets x = x + y (which is x = 20+35 = 55) (note: x was incremented, but assigned over top of, so doesn't matter)
y was incremented and is therefore 36
next line increments both, adds the result and sets it as y (which is y = 37 + 56 = 93)
which would be 56 and 93, so the output is 5693
I could see the VS answer making sense if the post-increment happened after the assignment. Is there some spec that makes one of these answers more right than the other? Is it just ambiguous? Should we fire anyone who writes code like this, making the ambiguity irrelevant?
Note: Initially, we only tried with gcc, however clang gives this warning:
coatedmoose#ubuntu:~/playground$ clang++ strange.cpp
strange.cpp:8:16: warning: multiple unsequenced modifications to 'x' [-Wunsequenced]
x = y++ + x++;
~ ^
1 warning generated.

The Clang warning is alluding to a clause in the standard, C++11 and later, that makes it undefined behaviour to execute two unsequenced modifications to the same scalar object. (In earlier versions of the standard the rule was different although similar in spirit.)
So the answer is that the spec makes all possible answers equally valid, including the program crashing; it is indeed inherently ambiguous.
By the way, Visual C++ actually does have somewhat consistent and logical behaviour in such cases, even though the standard does not require it: it performs all pre-increments first, then does arithmetic operations and assignments, and then finally performs all post-increments before moving on to the next statement. If you trace through the code you've given, you'll see that Visual C++'s answer is what you would expect from this procedure.

Related

Use of reference variables in C++ [duplicate]

This question already has an answer here:
Use pass by reference in recursion
(1 answer)
Closed 1 year ago.
I came across the following question:
#include <stdio.h>
int f(int &x, int c)
{
c = c - 1;
if (c == 0) return 1;
x = x + 1;
return f(x, c) * x;
}
int main()
{
int p = 5;
printf("%d", f(p, p));
}
As far as I have worked out, the recursion calls should work, and with each recursion call, value of c should reduce by 1 and value of x should increase by 1 . However, if I calculate it that way, the answer comes out to be 3024. However, on executing, the output comes out to be 6561. I am not really sure how this answer is coming.
I have the link to the article from where this question is taken, but I fail to understand how x will remain constant as is described in this link: https://www.geeksforgeeks.org/c-references-question-1/
Can someone help me with the working behind this code?
There can be any result, due to Undefined behavior.
Since the x is passed by reference, the last assign will matter. Thus, we have:
9*9*9*9*1=6561
We delay the evaluation of the f(x, c) * x, where all the subsequent recursive calls will have access to the x. We increment the x this way until the c is equal to 0, means we increment the x up to it being 9.
When we hit the base case (the c == 0), the current call returns 1, while the x is already 9.
Then we evaluate the multiplication 1 * x * x * x * x, where x is equal to 9. Thus, the 6561.
Flawless explanation? Not so much.
The fun part is that there is no concept of left-to-right or right-to-left evaluation in C++:
Order of evaluation of any part of any expression, including order of
evaluation of function arguments is unspecified (with some exceptions
listed below). The compiler can evaluate operands and other
subexpressions in any order, and may choose another order when the
same expression is evaluated again.
Means, that though this logic gets a pass this time, it may won't be this way next time for me or if you run it yourself.

Same code gives different output on Microsoft studio compared to other compilers [duplicate]

This question already has answers here:
How do we explain the result of the expression (++x)+(++x)+(++x)? [duplicate]
(5 answers)
Closed 3 years ago.
int a = 10;
a = a++;
cout << a<<" ";
a++;
cout << a;
In microsoft Visual its output is 11 12
And in other compilers (like codechef and codeforces) its output is 10 11
This question's Output was asked in some mcq paper and the correct answer is 10 11 but can any1 also explain how
a = a++;
++a;
cout<<a;
produces output of 11 does a = a++ does't do anything?
a = a++; is not a correct statement due to lack of sequence point or being unsequenced(C++11).
undefined behavior - there are no restrictions on the behavior of the program. Examples of undefined behavior are memory accesses outside of array bounds, signed integer overflow, null pointer dereference, more than one modifications of the same scalar in an expression without any intermediate sequence point (until C++11)that are unsequenced (since C++11), access to an object through a pointer of a different type, etc. Compilers are not required to diagnose undefined behavior (although many simple situations are diagnosed), and the compiled program is not required to do anything meaningful.
https://en.cppreference.com/w/cpp/language/ub

What is x after 'x += x--'? [duplicate]

This question already has answers here:
Undefined behavior and sequence points
(5 answers)
Closed 4 years ago.
Whats happening x after executing the code below;
int x = 10;
x += x--;
I'm expecting result 19 (adding x to x and then decrease x by 1) but result 20. How does it works behind the curtains? Thank your for your answers.
The behavior in this case was undefined before C++17, see e.g., https://en.cppreference.com/w/cpp/language/eval_order#Undefined_behavior , so if your compiler does not conform to it, it is no use testing or trying to understand it: it will depend on implementation, or even version of the compiler.
If your compiler conforms to C++17, it is guaranteed that in a simple or compound assignment (= or e.g. +=, respectively) all of the side effects of right hand side will be dealt with before evaluating the left hand side.
In your case, x-- is evaluated to be 10 accompanied by setting x=9 as its side effect, then the computer will add 10 to x=9 resulting in x=19.
Thanks to MichaƂ for his correction, which I incorporated into the answer.
Having an older c++ might probably not do the job as the behaviour is literally defined to be undefined, by the older standard. (Thanks to #LightnessRacesinOrbit)
If you just try out an online compiler which will have the latest version, it works just fine and the result is 19 as you expected (x+=x-- is the same as x= x+x--. This means for getting the new "x", it has to sum the old "x"+the old "x" -1. So it will do x+(x--), which is x=10+(9).
Try it out here:
with:
#include <iostream>
using namespace std;
int main()
{
int x = 10;
x += x--;
cout<<x<<endl;
}

Macros preincrement in c++ [duplicate]

This question already has answers here:
Undefined behavior and sequence points
(5 answers)
Closed 8 years ago.
1.macros has always been difficult.
2.Below is the code and output is 125 and 7....Please elaborate the working
#define mul(x) (x++ * ++x * x++)
#include<iostream.h>
void main()
{
int a=4,j;
j=mul(a);
cout<<j<<endl;
cout<<a<<endl;
}
Your program results in undefined behaviour. j could be anything.
Read more here: Undefined behavior and sequence points
What I believe is happening is this.
Set a to 4.
mul is called and a is passed in.
The second multiplication (++x) has the prefix incrementer, so x (a) is increased by 1. a is now 5.
The multiplication now happens. Since the first and last have the postfix incrementer, nothing happens until after the multiplication happens. So we have 5 * 5 * 5 = 125.
Since the multiplication is done now, the postfix incrementers happen which makes x (a) 6 and then 7.
j then equals 125.
???
Profit!
EDIT:
This is explaining the behavior that he is experiencing. I understand that this won't happen in every case.

Variable declaration as side-effect

So I'm looking over C++ operator rules as I do when my programs start behaving wonkily. And I come across the comma operator. Now, I have known it was there for a while but never used it, so I began reading, and I come across this little gem:
if (int y = f(x), y > x)
{
// statements that use y
}
I had never thought about using commas' first arguments' side-effects to get locally-scoped variables without the need for bulky block-delimited code or repeated function calls. Naturally, this all excited me greatly, and I immediately ran off to try it.
test_comma.cpp: In function 'int main()':
test_comma.cpp:9:18: error: expected ')' before ',' token
if (int y = f(x), y > x) {
I tried this on both a C and C++ compiler, and neither of them liked it. I tried instead declaring y in the outer scope, and it compiled and ran just fine without the int in the if condition, but that defeats the purpose of the comma here. Is this just a GCC implementation quirk? The opinion of the Internet seems to be that this should be perfectly valid C (and ostensibly, to my eye, C++) code; there is no mention of this error on any GCC or C++ forum that I've seen.
EDIT: Some more information. I am using MinGW GCC 4.8.1-4 on Windows 7 64-bit (though obviously my binaries are 32-bit; I need to install mingw-w64 one of these days).
I also tried using this trick outside of a conditional statement, as below:
int y = (int z = 5, z);
This threw up two different errors:
test_comma.cpp: In function 'int main()':
test_comma.cpp:9:11: error: expected primary-expression before 'int'
int y = (int z = 5, z);
^
test_comma.cpp:9:11: error: expected ')' before 'int'
With creative use of parentheses in my if statement above, I managed to get the same errors there, too.
Contrary to what several other people have claimed, declarations inside the if conditional are perfectly valid. However, your code is not.
The first problem is that you're not actually using the comma operator, but [almost] attempting to declare multiple variables. That is not valid in an if conditional. And, even if it were possible, your second declaration would be entirely broken anyway since you try to redeclare y, and you do so with > instead of =. It all simply makes no sense.
The following code is sort of similar:
if (int y = (f(x), y > x))
Now at least it's half-valid, but you're using y uninitialised and yielding undefined behaviour.
Declarations and expressions are not the same thing, so the following is quite different code:
int y = 0;
if (y = f(x), y > x)
Now you don't have a problem with uninitialised variables, either (because I initialised y myself), and you're getting this "side-effect declaration" that doesn't change the resulting value of the if conditional. But it's about as clear as mud. Look how the precedence forms:
int y = 0;
if ((y = f(x)), (y > x))
That's not really very intuitive.
Hopefully this total catastrophe has been a lesson in avoiding this sort of cryptic code in entirety. :)
You cannot declare variable and apply operator , simultaneously either you are declaring variable (in case of if it would be only one 'cause result needs to be resolved to bool), either you are writing some statement (also resolving to bool) which may include operator , in it.
You need to declare y on the top of if condition:
int y;
if(y=f(x),y>x)
{
}
This will check the last condition defined in the if condition and rest others are executed as general statements.