Ответ 1
Оператор sizeof
не оценивает свой аргумент, он только смотрит на тип своего операнда.
Скажем, у вас есть массив a
с типом "array [N] типа T". Тогда, в большинстве случаев, тип имени a
является "указателем на T" (T *
), а значение указателя является адресом первого элемента массива (&a[0]
). То есть имя массива "распадается" на указатель на его первый элемент. "Затухание" не происходит в следующих случаях:
- когда
a
используется с оператором address-of (&
), - при инициализации
a
(незаконно назначать массивы в C) и - когда
a
является операндом оператораsizeof
.
Итак, sizeof a
дает вам N
раз sizeof(T)
.
Когда вы выполняете sizeof(a-3)
, тип операнда до sizeof
определяется выражением a-3
. Так как a
в a-3
используется в контексте значение (т.е. Ни один из трех контекстов выше), его тип является "указателем на int", а name a
распадается на указатель на a[0]
. Таким образом, вычисление a-3
является undefined поведением, но поскольку sizeof
не оценивает его аргумент, a-3
используется только для определения типа операнда, поэтому код в порядке (см. Первую ссылку выше для более).
Из вышесказанного, sizeof(a-3)
эквивалентен sizeof(int *)
, который равен 4 на вашем компьютере.
"Преобразование" происходит из-за оператора вычитания. Вы можете увидеть аналогичный и, возможно, более неожиданный результат с помощью оператора запятой:
printf("%zu\n", sizeof(1, a));
также напечатает sizeof(int *)
из-за оператора запятой, в результате чего a
будет использоваться в контексте значений.