Раздел §6.5.3.2 "Операторы адреса и косвенности" ¶3 говорит (только для соответствующего раздела):
Унарный и оператор возвращает адрес своего операнда.... Если операнд является результатом унарного оператора
*
, ни этот оператор, ни оператор&
не оцениваются, и результат как бы опускался, за исключением того, что ограничения на операторы все еще применяются, и результат не является именующий. Аналогично, если операнд является результатом оператора[]
, ни оператор&
, ни унарный*
, который подразумевается[]
, не оцениваются, а результат выглядит так, как если бы оператор&
был удален и оператор[]
были заменены на a+
....
Это означает, что это:
#define NUM 10
int tmp[NUM];
int *i = tmp;
printf("%ti\n", (ptrdiff_t) (&*i - i) );
printf("%ti\n", (ptrdiff_t) (&i[NUM] - i) );
Должно быть совершенно законным, печатать 0 и NUM
(10). Стандарт кажется очень ясным, что оба этих случая должны быть оптимизированы.
Однако, похоже, для оптимизации не требуется следующее:
struct { int a; short b; } tmp, *s = tmp;
printf("%ti\n", (ptrdiff_t) (&s->b - s) );
Это кажется ужасно непоследовательным. Я не вижу причин, чтобы приведенный выше код не печатал дополнение sizeof(int)
plus (маловероятное) (возможно, 4).
Упрощение выражения &->
будет таким же концептуальным (IMHO) как &[]
, простым адресом-плюс-смещением. Это даже смещение, которое будет определяться во время компиляции, а не потенциально runtime с оператором []
.
Есть ли что-нибудь в обосновании того, почему это так кажется непоследовательным?