7

I understand that this is undefined behavior:

int i = 0;
int a[4];
a[i] = i++;  //<--- UB here

because the order of evaluation of i for the left hand side and the right hand side are undefined (the ; is the only sequence point).

Taking that reasoning a step further it seems to me that this would be undefined unspecified behavior:

int i = 0;

int foo(){
    return i++;
}

int main(){
    int a[4];
    a[i] = foo();
    return 0;
}

Even though there are a few sequence points on the right hand side of the = as far as I understand it is still undefined unspecified whether f() or a[i] is evaluated first.

Are my assumptions correct? Do I have to take painstaking care when I use a global or static variable on the left hand side of an assignment that the right hand does not under any circumstances modify it?

odinthenerd
  • 5,422
  • 1
  • 32
  • 61
  • The order of evaluation is unspecified, not undefined. – chris Apr 08 '14 at 14:58
  • The sequencing in the function is for the function only. It's not defined which will happen first, the dereferencing of `a` or the function call. – Some programmer dude Apr 08 '14 at 15:00
  • @chris thanks for your correction, is my fix correct? i.e. is the first one undefined and the second unspecified? – odinthenerd Apr 08 '14 at 15:07
  • @PorkyBrain, There's still one just under the first snippet, but I'm with jrok on the answer. You won't know what value it gets, but it will have one of two possible values. – chris Apr 08 '14 at 15:21

2 Answers2

6
a[i] = foo();

Here it is unspecified whether foo or a[i] is evaluted first. In the new C++11 wording, the two evaluations are unsequenced. That alone doesn't cause undefined behaviour, though. It is when there are two unsequenced accesses to the same scalar object, at least one of which is writing, where it does. That's why a[i] = i++; is UB.

The difference between these two statements is that a call to foo() does introduce a sequence point. C++11 wording is different: executions inside a called function are indeterminately sequenced with respect to other evaluations inside the calling function.

This means there's a partial ordering between a[i] and i++ inside foo. As a result, either a[0] or a[1] will get set to 0, but the program is well defined.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
jrok
  • 54,456
  • 9
  • 109
  • 141
1
a[i] = i++;

This is undefined behavior because the value of i is both modified and accessed between two sequence points (and the access is not directly involved in the computation of the next value of i). This is also unspecified behavior, because the order of evaulation is unspecified (the increment of i can happen before or after using i as the index into a).

When you introduce a function call, like :

a[i] = foo();

the function call introduces two further sequence points : one before the function is entered, and one after the function has returned.

This means that the increment of i inside the function is surrounded by two sequence points, and does not cause undefined behavior.

It is still unspecified behavior though whether the function call will be done before using i as an index on the left-hand side of the assignment, or after.

Sander De Dycker
  • 16,053
  • 1
  • 35
  • 40