9

UPDATE: As marked by user ecatmur, it's a duplicate of In C99, is f()+g() undefined or merely unspecified? (although the questions asks about C99, but answer is unchanged for C++). And the answer is: unspecified (for both cases).


Consider following C++14 code fragment:

int i = 0;
int x() { i++; return i;}
int y() { i++; return i;}
bool z = (x() > y());  // unspecified or undefined ?

Is the value of z merely unspecified, or is this undefined behavior ?

As per my understanding (please correct if I am wrong), an expression of the kind: i++ > i++ will be undefined behavior, as we are mutating same variable twice between a pair of sequence points, but what about the case above (where mutation happen in separate functions) ?

And what about this one:

bool z = (x() > i++);  // undefined or unspecified now ?
Community
  • 1
  • 1
abi
  • 1,368
  • 10
  • 12
  • 1
    Operations in a function are sequenced before the use of the return value. – chris Mar 02 '15 at 18:35
  • 1
    @chris: True, but the question is about whether the function calls (and hence the various accesses to `i`) are sequenced with respect to each other. – Mike Seymour Mar 02 '15 at 18:36
  • @MikeSeymour, True. I really want to say it isn't undefined, but I'll need to go find the text. – chris Mar 02 '15 at 18:42
  • @chris: I thought the function calls/returns act like sequence points. – Karoly Horvath Mar 02 '15 at 18:45
  • @KarolyHorvath, That's what I was remembering. It is right there in C++03: "There is also a sequence point after the copying of a returned value and before the execution of any expressions outside the function", but C++11 has pretty different text in that section. – chris Mar 02 '15 at 18:47
  • @chris if I read the it correctly, C++11, 1.9/15 seems to say it is undefined: Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced [...] If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object [...] the behavior is undefined. – Come Raczy Mar 02 '15 at 18:48
  • @KarolyHorvath They are, the issue here is that `x()` and `y()` are indeterminably sequenced, i.e. either may occur before the other, and each call involves a side effect on `i`. The order of evaluation of `x()` and `y()` is unspecified, so I believe chris is right, the value of `z` is also unspecified, not undefined. – Praetorian Mar 02 '15 at 18:48
  • @ComeRaczy, Except this *is* noted, as Mike's answer shows. I certainly didn't read that part well enough the first time. – chris Mar 02 '15 at 18:49

2 Answers2

15

In both cases, the value is unspecified, but behaviour is well-defined. Function calls are indeterminately sequenced with respect to other evaluations in the expression that calls them, as specified in [intro.exececution] 1.9/15:

Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function

So all accesses to i are sequenced, giving well-defined behaviour, but the sequence is indeterminate, giving an unspecified value.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • Isn't that still undefined behavior? [dcl.init]/12 "If an indeterminate value is produced by an evaluation, the behavior is undefined" – David G Mar 02 '15 at 19:00
  • @0x499602D2, I don't think it's the same kind of indeterminate value as `int i;`, just that there are two possible values and you can't rely on which you'll get. – chris Mar 02 '15 at 19:03
  • 4
    @0x499602D2: The value is unspecified (i.e. valid but unknown) not indeterminate (potentially invalid, e.g. the value of an uninitialised variable, which is what [dcl.init] is talking about). – Mike Seymour Mar 02 '15 at 19:04
0

It is unspecified behavior.

Reference: http://en.cppreference.com/w/cpp/language/eval_order :

The order of evaluation of the subexpressions within any expression is unspecified

Both bool z = (x() > y()); and bool z = (x() > i++); are unspecified behavior.
The only assumption you can do is x() and y() will be processed before >.
There is no guarantee for anything else.

Telokis
  • 3,399
  • 14
  • 36