Masaki Hara Masaki Hara - 2 months ago 17
C Question

Does a[a[0]] = 1 produce undefined behavior?

Does this C99 code produce undefined behavior?

#include <stdio.h>

int main() {
int a[3] = {0, 0, 0};
a[a[0]] = 1;
printf("a[0] = %d\n", a[0]);
return 0;
}


In the statement
a[a[0]] = 1;
,
a[0]
is both read and modified.

I looked n1124 draft of ISO/IEC 9899. It says (in 6.5 Expressions):


Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be read only to determine the value to be stored.


It does not mention reading an object to determine the object itself to be modified. Thus this statement might produce undefined behavior.

However, I feel it strange. Does this actually produce undefined behavior?

(I also want to know about this problem in other ISO C versions.)

M.M M.M
Answer

the prior value shall be read only to determine the value to be stored.

This is a bit vague and caused confusion, which is partly why C11 threw it out and introduced a new sequencing model.

What it is trying to say is that: if reading the old value is guaranteed to occur earlier in time than writing the new value, then that's fine. Otherwise it is UB. And of course it is a requirement that the new value be computed before it is written.

(Of course the description I have just written will be found by some to be more vague than the Standard text!)

For example x = x + 5 is correct because it is not possible to work out x + 5 without first knowing x. However a[i] = i++ is wrong because the read of i on the left hand side is not required in order to work out the new value to store in i. (The two reads of i are considered separately).


Back to your code now. I think it is well-defined behaviour because the read of a[0] in order to determine the array index is guaranteed to occur before the write.

We cannot write until we have determined where to write. And we do not know where to write until after we read a[0]. Therefore the read must come before the write, so there is no UB.

Someone commented about sequence points. In C99 there is no sequence point in this expression, so sequence points do not come into this discussion.