A question about post increment

Hello, so I was review some basic stuff to see if I completely understand the concept and there is something I do not seem to understand.

So I have this little program
1
2
3
4
5
6
int main()
{
     int i = 1;
     cout << i << " " << i++;
     return 0;
}


I was expecting
 1 1
as output because the post increment would output the i before calculating however I get this instead
2 1 
Could someone explain to me why this happen? Thank you.
Line 4 is a sequence of function calls; it could be (theoretically) rewritten like so:

1
2
3
4
5
int main()
{
    int i=1 ;
    operator<<(operator<<(operator<<(cout, i), " "), i++) ;
}


I say theoretically because operator<< may be an overloaded member function of the ostream object, which would require different semantics, but the gist is still the same.

The order of the evaluation of expressions used as arguments to function calls is not specified, so they may be evaluated in any order.

The following would be better advised:

1
2
3
4
5
6
7
int main()
{
     int i = 1;
     cout << i << " " ;
     cout  << i++;
     return 0;
}
(I can see from Google that this issue confuses a lot of people...)

If you are using GCC, which I think you are (VC++ gives me "1 1" for your program, but GCC "2 1"), then you should probably add the following flags to your compiler build settings (if you don't already have them):

-Wall -Wextra -pedantic

With your little program, GCC gives me the warning

main.cpp:7:36: warning: operation on 'i' may be undefined [-Wsequence-point]

The "sequence points" that the GCC messages are another part of the picture.

In addition to the indeterminant order of evaluation of function parameters (which cire has already pointed out), you are not allowed to modify a variable more than once without an intervening sequence point (to more or less quote the stock phrase.)

If you haven't read up about sequence points yet, then see:

Sequence point
http://en.wikipedia.org/wiki/Sequence_point

(The article discusses ambiguity, etc.)

And in a similar vein, the answer this tiny program displays

1
2
3
4
5
6
7
8
9
10
#include <iostream>
using namespace std;

int main()
{
    int j = 1;
    int k = j++ + j++ + j++ + j++;
    cout << k << "\n";
    return 0;
}


is...

4


(for both GCC and VC++)

Andy

PS The answer in this stackoverflow.com thread might also be of interest as it quotes the appropriate bits of the C++ standard:

Behavior of post increment in cout [duplicate]
http://stackoverflow.com/questions/3986361/behavior-of-post-increment-in-cout
Last edited on
If you are using GCC, which I think you are (VC++ gives me "1 1" for your program, but GCC "2 1"), then you should probably add the following flags to your compiler build settings (if you don't already have them)


VC++ actually gives me "1 1" with optimizations enabled, "2 1" without.
Sequence point rules existed in C++ prior to 2011.

Now, order of evaluation is governed by 'sequenced-before rules'

See: http://en.cppreference.com/w/cpp/language/eval_order
(The obsoleted sequence-point rules (applicable to C++98) are given at the end of the page).
oops - didn't check enough configs. GCC 4.6.2 (MinGW) give me the same results for -O0, -O1, -O2 and -O3; but VC++ 2010 is different between /Od and the rest: /O1, /O2 and /Ox.

For GCC (all cases) and VC++ /Od

<< i   << i++               => 2 1
<< i++ << i                 => 1 2
<< i++ << i++               => 2 1
<< i++ << i   << i          => 1 2 2
<< i++ << i++ << i          => 2 1 3
<< i++ << i++ << i++        => 3 2 1
<< i++ << i   << i   << i   => 1 2 2 2
<< i++ << i++ << i   << i   => 2 1 3 3
<< i++ << i++ << i++ << i   => 3 2 1 4
<< i++ << i++ << i++ << i++ => 4 3 2 1

(I like the last one of this set!)

But VC++ /O1, /O2, /Ox

<< i   << i++               => 1 1
<< i++ << i                 => 1 2
<< i++ << i++               => 1 1
<< i++ << i   << i          => 1 2 2
<< i++ << i++ << i          => 1 1 3
<< i++ << i++ << i++        => 1 1 1
<< i++ << i   << i   << i   => 1 2 2 2
<< i++ << i++ << i   << i   => 1 1 3 3
<< i++ << i++ << i++ << i   => 1 1 1 4
<< i++ << i++ << i++ << i++ => 1 1 1 1

(I didn't go on to cycle though any other compiler flags...)

Andy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// code used : an appalling case of cut & paste.
//
#include <iostream>
#include <iomanip>
#include <cstring>
using namespace std;

int main()
{
	const size_t width = strlen("<< i++ << i++ << i++ << i++");

	cout << left;

	{
		int i = 1;
		cout << setw(width) << "<< i   << i++" << " => ";
		cout << i   << " " << i++ << "\n";
	}

	// etc

	{
		int i = 1;
		cout << setw(width) << "<< i++ << i++ << i++ << i++" << " => ";
		cout << i++ << " " << i++ << " " << i++ << " " << i++ << "\n";
	}

	return 0;
}


Last edited on
Thank you so much everyone, now I understand why this happen.
There is really no point in trying to see what the compilers do in cases of undefined (not unspecified) behavior: it's kind of like setting fire to things and watching them burn... which can be fun

Taking andy's program (indeed, that was a lot of cut-and-paste), here are a few more compilers I have at hand (always highest optimization, no point using C++ otherwise)

                               (1)      (2)      (3)      (4)
<< i   << i++               => 2 1      2 1      1 1      2 1
<< i++ << i                 => 1 2      1 2      1 2      1 2     
<< i++ << i++               => 1 1      2 1      1 2      1 2     
<< i++ << i   << i          => 1 2 2    1 2 2    1 2 2    1 2 2     
<< i++ << i++ << i          => 1 1 3    2 1 3    1 2 3    1 2 3     
<< i++ << i++ << i++        => 1 1 1    3 2 1    1 2 3    1 2 3     
<< i++ << i   << i   << i   => 1 2 2 2  1 2 2 2  1 2 2 2  1 2 2 2     
<< i++ << i++ << i   << i   => 1 1 3 3  2 1 3 3  1 2 3 3  1 2 3 3     
<< i++ << i++ << i++ << i   => 1 1 1 4  3 2 1 4  1 2 3 4  1 2 3 4     
<< i++ << i++ << i++ << i++ => 1 1 1 1  4 3 2 1  1 2 3 4  1 2 3 4     

(1) gcc-4.8.1/linux
(2) gcc-4.7.2/linux
(3) clang++/linux, intel/linux, gcc/aix, xlc/aix (boring!)
(4) sun studio/sparc

Last edited on
Topic archived. No new replies allowed.