nasenbaer
nasenbaer

Reputation: 33

c++ evaluation of ambigous sum expression

Take the following example:

int g_X;
int func() {
 return ++g_X;  // using g_X++ is not an option
}
int main() {
 g_X = 0;
 int a = g_X + func();
 g_X = 0;
 int b = func() + g_X;
 g_X = 0; int temp = g_X;
 int c = temp + func();

 return 0;
}

a and b are both 2, c has the expected value 1 (tested with Visual Studio 2010 to 2015). I read that sums are not associated with a sequence point (e.g. https://en.wikipedia.org/wiki/Sequence_point) and therefore the order is not fixed. Yet I thought that the value of g_X gets captured before the function call. Am I really in undefined behavior territory or is there some way not having to use the temp var?

Upvotes: 3

Views: 113

Answers (2)

vitaut
vitaut

Reputation: 55554

At first sight this looks like an undefined behavior because, quoting §1.9/15:

If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined.

and your example seemingly satisfies these conditions:

  1. Evaluation of operands of + operator are unsequenced relative to each other (but see below).
  2. There is a side effect on a scalar object (func increments g_X).
  3. There is a computation using the value of the same scalar object (g_X).

On the other hand, as pointed out in the Brian's answer, function call does introduce sequencing, although indeterminate. According to this argument this is not an undefined behavior, but merely unspecified.

Upvotes: 2

Brian Bi
Brian Bi

Reputation: 119144

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.

([intro.execution]/15)

Therefore, in an expression of the form g_X + func() or func() + g_X, it's true that the + operator doesn't introduce any sequencing constraint, but nevertheless the access to g_X within main either happens before or after the body of func(), you just can't predict which. This implies that the behaviour is defined, but whether a is 1 or 2 is unpredictable. Likewise, whether b is 1 or 2 is unpredictable.

Upvotes: 2

Related Questions