Is one side of an assignment sequenced before the other?
Asked Answered
N

2

8

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 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 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?

Naevus answered 8/4, 2014 at 14:53 Comment(1)
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.Compact
D
6
a[i] = foo();

Here, since C++17 the evaluation of foo() is sequenced before a[i].

Before C++17, it was unspecified whether foo or a[i] is evaluated first (they are unsequenced relative to each other). 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 executions inside a called function are indeterminately sequenced with respect to other evaluations inside the calling function (rather than being unsequenced). Or in pre-C++11 terms, the call to foo() introduces a sequence point.

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.

Dionysian answered 8/4, 2014 at 15:7 Comment(0)
K
2
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.

Koren answered 8/4, 2014 at 15:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.