Who explains the behavior of this, please:
unsigned int q = 0;
cout << q++ << " " << q++ << endl;
cout << q << " " << q++ << endl;
cout << q++ << " " << q << endl;
cout << ++(q += ++q) << " " << ++ ++q << endl;
Who explains the behavior of this, please:
unsigned int q = 0;
cout << q++ << " " << q++ << endl;
cout << q << " " << q++ << endl;
cout << q++ << " " << q << endl;
cout << ++(q += ++q) << " " << ++ ++q << endl;
There is not much to explain ... each one will give a different result.
The first line can be 00
, 01
, 10
, ... and something similar to the following and this is so because C ++ focused on performance and, consequently, leaves a lot of room for maneuver to compilers when optimizing certain sets of instructions.
Effectively in C ++, q++
is an instruction with a postincremento , so if we do this:
int q=0;
std::cout << q++;
std::cout << q++;
We see that the sequence 01
is actually printed ... however, the instruction std::cout << q++ << q++;
gives an indeterminate result why?
Basically because the standard clearly indicates that in a post-increment the variable is first evaluated and then the increase ... but it says absolutely nothing about when that increment must be executed ... well yes, it says one thing and that is must be executed before the next sequence point ...
In this case the sequence points are established at the end of each instruction (the semicolon), then the post-increments can be executed at any time between the evaluation of the variable and the end of the instruction.
On the other hand ... it could not be otherwise, the order in which the variables are evaluated is indeterminate, so the first line of your code could end up being one of these cases:
Case 1: postincrements at the end
std::cout << q;
std::cout << q;
++q;
++q;
Case 2: evaluation from left to right
std::cout << q;
++q;
std::cout << q;
++q;
Case 3: evaluation from right to left
int temp = q;
++q;
std::cout << q;
std::cout << temp;
++q;
And with the rest of the instructions more of the same ... so you know, do not do this kind of thing in the code because the result will be unpredictable.
Some additional clarifications:
versions before C ++ 11
In these versions the sequence points are defined such that:
At certain specified points in the execution sequence called sequence points, all side effects of previous evaluations shall be complete and no side effects of subsequent evaluations shall have taken place. (§1.9 / 7)
What comes to say the following:
A sequence point is a specific point in the execution in which the side effects of the previous evaluations must be complete. Evaluations after this point will have no effect on the previous evaluations.
As you can see it refers to side effects ... What is this?
Side effects are changes that occur in the state of the application (that is, variables that change their value) and that may affect the execution result. As an example, use the first line of the question code:
cout << q++ << " " << q++ << endl;
Here are two side effects that are the two increments of q
. They are side effects because it is not specified at what specific moment they should be executed. We only know that there are operations that will have been executed yes or yes upon reaching the semicolon that delimits the line of code.
What sequence points can we find?
A && B
A || B
A ? B : C
operator comma: A , B
.
Not applicable when the comma acts as a separator , for example in function calls: func(A,B)
For giving some examples of non-indefinite behavior :
int a = 0;
bool b = a++ || a++; // a = 2
b = a++ || a++; // a = 3 <--- la expresión sufre cortocircuito
b = a++ && a++; // a = 5
a++, a++; // a = 7
a++ ? a++ : a=0; // a = 9
Undefined Behaviors :
int a=0;
int b = a++ + a++;
func(a++,a++);
b = (a++ + a++) + a++;
C ++ 11 and up
In C ++ 11 the concept of sequence point disappears. Its scope is divided into three different elements to better identify each behavior although the behavior is exactly the same:
Adding little ... Here I explain the behavior I got from your code.
The increase operator ++
in both C and C ++ act as follows (I assume you already know) :
For what we have:
unsigned q = 0;
cout << q++ << endl;
cout << ++q << endl;
Will print:
0
2
At the moment of printing the q++
, the operator ++
is responsible for returning the value of q and then increasing its value, so you never see the 1 on the screen, when it is time to make ++q
, first it is increased and then it shows on the screen the value of 2.
Applied to your code, it could be said that (...) :
Prints the value of q
, then increases its value (which is now 1) , prints again the value of q
and finally, increases its value; in this example, q
has the value of 2 at the end:
cout << q++ << " " << q++ << endl;
Print the value of q
(If we follow the sequence, it is 2) , then print again its value (2) and then increase the variable (So that its value is 3 now) :
cout << q << " " << q++ << endl;
Print again the value of q
and increase so that its value is 4 and then print its value:
cout << q++ << " " << q << endl;
Finally: What you do here is beautifully horrifying (IMHO) , first pre-increase the value of q
to add it and assign it to q
, which is then increased, leading to a: ++(4 += ++4)
that would be simplified to: ++(5 += 5)
and finally ++(10)
, after printing this value (In my case 11) , ++ ++q
is executed evaluating ++ ++11 -> ++ 12 -> 13
:
cout << ++(q += ++q) << " " << ++ ++q << endl;
This has been the result that the ideone has thrown at me and is how it mentions eferion in your answer, all this is totally dependent on compiler the fact of applying these optimizations, even of platform.
You can try with printf
of cstdio
and you will see a totally different result.