0

Possible Duplicate:
Could anyone explain these undefined behaviors (i = i++ + ++i , i = i++, etc…)

For the code below:

main() {

int i = 1 ;

cout << i << ++i << i++ ;

}

Why do I get the output as 331 instead of what was expected i.e 122 ?

( Same is the case even if I use printf instead of cout ?)

Community
  • 1
  • 1
cirronimbo
  • 909
  • 9
  • 19
  • @chris: are you sure? The operator seems like introducing a sequence point. – Daniel Jun 07 '12 at 04:15
  • @Dani, It actually might be. I might have jumped too quickly. – chris Jun 07 '12 at 04:17
  • @Dani: It's not(a sequence point). You are right chris. – Benjamin Lindley Jun 07 '12 at 04:20
  • @BenjaminLindley, after seeing two similar answers from Ks of rep people and a caution from another, I started to wonder if it was actually different in this case. – chris Jun 07 '12 at 04:24
  • 1
    @chris: Here's the thing that I think gets a lot of people confused. There is definitely a sequence point in the function calls themselves. That is to say, the first `<<` is definitely called before the second, which is definitely called before the third. But that says nothing about the order in which their arguments are evaluated, so there is no sequence point there(between arguments). – Benjamin Lindley Jun 07 '12 at 04:27
  • @chris and Benjamin_ As stated here : "http://en.wikipedia.org/wiki/Sequence_point" , "(In C++, overloaded operators act like functions, and thus operators that have been overloaded introduce sequence points in the same way as function calls.)", which is to say that operator << definitely introduces seq.pts. But the problem basically seems to be with the way << is working, I mean the three << operators are acting much like a recursive function call ( the way Zero stated and almost convinced me with, in the last answer, down the page ) – cirronimbo Jun 07 '12 at 05:27
  • 1
    The moderators have a funny definition of `exact`. The answer may be the same, but the question certainly isn't. Is it reasonable to expect someone who needs to ask this question to recognized the linked question as an answer? I don't think so. – Zero Jun 07 '12 at 07:53

4 Answers4

4

<< is a function, namely something like ostream& operator<<(ostream& lhs, RhsType rhs).

cout << a;

is equivalent to

operator<<(cout, a);

The function returns lhs, that is return lhs, - so in the above examples cout is returned.

So your example

cout << i << ++i << i++ ;

is equivalent to

operator<<(operator<<(operator<<(cout, i), ++i), i++);

Correction C++ does not specify which order the increment operations are performed. It seems logical to you and me that the most nested would go first, but as far as the compiler is concerned it is free to execute the increment whenever it likes. It is the same behaviour as a function like myFunc(cout, i++, ++i, i) where the order in which the increments are evaluated is undefined. The only thing guaranteed is the functions are evaluated inside to outside.

Zero
  • 11,593
  • 9
  • 52
  • 70
  • okay.. So its much like a recursive function call forming a LIFO stack. – cirronimbo Jun 07 '12 at 05:01
  • It's not really a recursive call, because `operator<<` doesn't call `operator<<` again. It's usually called syntactic sugar: when the compiler sees A << B is changes it to operator<<(A, B). Since you have three `<<` there must be three calls to `operator<<`. – Zero Jun 07 '12 at 05:19
  • The order in which the arguments of a function call are evaluated is unspecified. So in `operator<<(operator<<(operator<<(cout, i), ++i), i++);`, the compiler is free to evaluate either argument first, `operator<<(operator<<(cout, i), ++i)` or `i++`. In this case, the second argument `i++` was evaluated first. The same holds for the first argument of the outermost call, `++i` was evaluated first there. In the `printf` version, `i` is changed multiple times without a sequence point in between, and that is explicitly undefined behaviour, nasal demon territory. – Daniel Fischer Jun 07 '12 at 12:46
3

The compiler is free to change the order of evaluation. You are changing i multiple times on the same statament which causes undefined behaviour.

fbafelipe
  • 4,862
  • 2
  • 25
  • 40
  • 1
    Slight correction. Technically there is not a problem with changing a value multiple times in one statement, as long as there is a sequence point between the two. For example, using the comma operator: `++i, i++;` – Benjamin Lindley Jun 07 '12 at 04:24
0

This is the reason why you should not write such code. I'm sure this will give you different results with different compilers. Using Visual C++ this gives you different output when run in Debug and Release versions.

Superman
  • 3,027
  • 1
  • 15
  • 10
0

The output you observed can be explained in this way: The expression is evaluated right-to-left *before* being passed to cout or printf for output.

Starting value is 1

i++ is post increment, ie it will print the value (1) and then increment to 2: output 1

++i is pre-incremen, so 2 becomes 3 before it is printed: output 3

finally, the current value of i (3) is printed: output 3

These respective values are passed to the output routine.

To clarify, my answer only tries to explain the observed behavior, not lay down hard and fast rules for how the compiler or output routines order their evaluations/actions.

Having said that, this type of code is not good practice and quite likely to cause all sorts of problems that could be avoided.

Levon
  • 138,105
  • 33
  • 200
  • 191
  • You probably mean to say the expression is evaluated "right-to-left" before being passed to cout, and output is printed in normal "left-to-right" manner ? – cirronimbo Jun 07 '12 at 04:24
  • @cirronimbo .. ooops, right you are, thanks for catching that (very late here :) – Levon Jun 07 '12 at 04:25
  • But is this "right-to-left" pre-evaluation an attribute of cout and printf only, or is it some sort of "general" rule ? – cirronimbo Jun 07 '12 at 04:28
  • @cirronimbo: It is neither a general rule, nor an attribute of cout and printf. There is no reason it has to occur this way, it is undefined behavior. Levon is just guessing what is happening. – Benjamin Lindley Jun 07 '12 at 04:30
  • 1
    @cirronimbo .. I agree with BenjaminLindley .. my answer only tried to explain the observed behavior, not lay down hard and fast rules for how the compiler or output routines order their evaluations/actions – Levon Jun 07 '12 at 04:31
  • @Levon_ Actually I too had figured this out (what you explained in your answer), and was askin the reason for that, which now certainly seems non-existing, as told by Benjamin also. thanks anyway :) – cirronimbo Jun 07 '12 at 04:37