Раздел §6.5.3.2 «Операторы адреса и косвенного обращения» ¶3 говорит (только соответствующий раздел):
Унарный оператор & возвращает адрес его операнд. ... Оператор возвращает адрес своего операнда. ... Оператор возвращает адрес своего операнда. ... Если операнд является результатом унарного оператора
*
, ни этот оператор, ни оператор&
не оцениваются, и результат такой, как если бы оба были опущены, за исключением того, что ограничения на операторы все еще применяется, и результат не является lvalue. Точно так же, если операнд является результатом оператора[]
, ни оператор&
, ни унарный*
, подразумеваемый[]
, не оцениваются, и результат будет следующим: если оператор&
был удален, а оператор[]
был изменен на оператор+
. ...
Это означает, что это:
#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 и ЧИСЛО
(10). Стандарт кажется очень ясным, что оба этих случая необходимо оптимизировать.
Однако это не так. Похоже, для оптимизации требуется следующее:
struct { int a; short b; } tmp, *s = tmp;
printf("%ti\n", (ptrdiff_t) (&s->b - s) );
Это кажется ужасно непоследовательным. Я не вижу причин, по которым приведенный выше код не должен печатать sizeof (int)
плюс (маловероятно) заполнение (возможно 4).
Упрощение выражения & ->
- это концептуально будет таким же (IMHO), что и и []
, простой адрес плюс смещение. Это даже смещение, которое будет определяться во время компиляции, а не во время выполнения с помощью оператора []
.
Есть ли какое-нибудь объяснение того, почему это кажется непоследовательным?