0

Possible Duplicates:
Multiple increment operators in single statement
Undefined Behavior and Sequence Points

can someone explain to me why this line of code generate such output? code (after initilizeing both i&j to zero):

cout<<i++<<','<<++j<<','<<--i<<','<<j--<<'\n';

output:

-1,0,0,0;

I know i++ means evaluate first then increase by 1, while ++i means increase by 1 then evaluate. but not sure what behavior is the multiple evaluation in a sequenced cout statement.

thanks!

Community
  • 1
  • 1

2 Answers2

6

The behavior of that code is undefined. An implementation is allowed to evaluate i++ before --i, or after it, or to stagger the evaluations such that the end results seem to make no sense at all.

It's even legal for an optimizer, when faced with code such as

if( k != 0 ) {
   cout << i++ << --i;
}
foofum(k);

to reason that because the code in the then branch is undefined behavior, then we can conclude that k is always zero, and reduce the entire thing to

foofum(0);

(This would be formally justified by the fact that the "undefined" behavior of the unsequenced updates to i just might happen to be assigning 0 to k and jumping to the closing brace. Undefined really does mean anything can happen).

Just don't write code like that.

Edit: It was suggested in a now-deleted answer that the effect of the statement is merely unspecified because the overloaded <<'s are function calls rather than native operators. However, that just makes the statement equivalent, for our present purposes, to

f(g(i++), i--);

(here the f represents a one-argument ostream::operator<<(), but the rules for evaluation order for AAA.f(BBB) and f(AAA,BBB) are the same). The compiler can decide in which order it evaluates the arguments to f. If it happens to evaluate i-- first, the evaluation order becomes:

  • i--
  • i++
  • sequence point
  • call g
  • sequence point
  • call f

Since there is no sequence point separating i-- and i++, undefined behavior results.

On the other hand, f(g(i+=h()), i++) is arguably merely unspecified under the sequence-point formalism. I think it reverts to undefined in C++1x's relational formulation.

hmakholm left over Monica
  • 23,074
  • 3
  • 51
  • 73
  • 1
    Not true. These are overloaded operators, so there is a sequence point at each one. (However, I entirely agree that one shouldn't write code like this.) – Oliver Charlesworth Aug 29 '11 at 16:24
  • I see. thank you! I was just curious as I read to this part. So for the same reason I shall not edit a variable multiple times in a comma seperated statement either, right? edit the same variable in multiple occasions must be seperated by semicolumn to get the intended results I assume. – string_is_hard Aug 29 '11 at 16:27
  • @string: Yes, you shouldn't do this. But not for the reason suggested in this answer! – Oliver Charlesworth Aug 29 '11 at 16:35
  • But the compiler is allowed to evaluate **all** the parameters before calling the first function. That can cause `i++` and `--i` to happen without an intervening sequence point. – Bo Persson Aug 29 '11 at 16:41
  • @string, the _comma operator_ is special; it does sequence its two subexpressions. So `i++, i--;` is a well-defined _statement_. However, the comma operation is _different from_ the comma that separates function arguments: `f(i++,i--)` has undefined behavior. – hmakholm left over Monica Aug 29 '11 at 16:54
  • @Henning: It turns out we are both wrong! As Ben points out in a comment to my answer, the overloads in question only take a single argument. So e.g. your code snippet is equivalent to `cout.op(i++).op(i--)`. Which ought to be well-defined, I think. – Oliver Charlesworth Aug 29 '11 at 17:09
  • @Oli: That's two arguments. cout is the first one. – Benjamin Lindley Aug 29 '11 at 17:12
  • @Benjamin: No, because that overload is a member function of `ostream`, not a free function. So it's `ostream::operator<<(int)`, not `operator<<(ostream &, int)`. – Oliver Charlesworth Aug 29 '11 at 17:13
  • @Oli, I'm not sure that makes any difference because the order of evaluation is just as unspecified between the base expression (implicit `this` parameter) and the visible argument list. (C++1X §5.2.2.8). – hmakholm left over Monica Aug 29 '11 at 17:13
  • @Oli: It results in the same thing when used in expressions, whether a free function or a member. – Benjamin Lindley Aug 29 '11 at 17:15
  • @Henning: Are you suggesting that in `x.f().g(y)`, it's unspecified whether `x.f()` or `y` is evaluated first? There's definitely a sequence point, so it's not undefined. – Oliver Charlesworth Aug 29 '11 at 17:16
  • 1
    @Oli, yes -- `f()` and `y` are unsequenced wrt each other. That much seems to be clear in the standard. – hmakholm left over Monica Aug 29 '11 at 17:18
  • @Henning: Indeed. I'd like to remove my -1 from your answer now, but it's timed-out because you haven't edited in the last 5 minutes. If you add some info that explains this, then I'll give you a +1 instead! – Oliver Charlesworth Aug 29 '11 at 17:24
2

The order of evaluation of arguments to a function in C/C++ is Unspecified.
The order in which arguments are being passed to << is Unspecified here and hence the result.

Alok Save
  • 202,538
  • 53
  • 430
  • 533