Although the C Standard defines the behavior of the []
operator in terms of the pointer addition and dereference operators +
and *
, +
and unary *
operators, such that that array[i]
means *(array+i)
, neither clang nor gcc actually processes it that way. The behaviors are identical in circumstances where both operators would yield defined behavior, but they interact differently with the compilers' interpretation of the "strict aliasing rule".
The Standard, for example, makes no general allowance for accessing union objects using member-type lvalues. Given a declaration like:
union blob { unsigned short hh[4]; unsigned ww[2]; } u;
it would be absurd to suggest that the only way of accessing those members would be by using character pointers or functions like memcpy
, especially since the Standard explicitly allows type punning via union objects. On the other hand, if one tests in gcc the functions:
int test1(int i, int j)
{
u.hh[i] = 1;
u.ww[j] = 2;
return u.hh[i];
}
int test2(int i, int j)
{
*(u.hh+i) = 1;
*(u.ww+j) = 2;
return *(u.hh+i);
}
both compilers will generate code for test1
that accommodate the possibility of type punning, but will generate for test2
code that unconditionally returns 1. This is allowable because the Standard characterizes both forms as Undefined Behavior so as to allow implementations to--on a Quality of Implementation basis--support whichever form(s) their customers would find useful.
While I don't know about how the behaviors compare in the particular expression you list, the fact that they interpret []
differently from a combination of +
and *
means that the Standard's definition of the former in terms of the latter should not be taken as an indication that they will be processed identically.