Оператор sizeof
не оценивает свой аргумент, он только looks at the type своего операнда.
Предположим, у вас есть массив a
с типом «массив [N] типа T». Затем в большинстве случаев тип имени a
является «указателем на T» (T *
), а значение указателя является адресом первого элемента массива (&a[0]
). То есть имя массива «распадается» на указатель на его первый элемент. «Затухающих» не происходит в следующих случаях:
- когда
a
используется с Адресов (&
) оператора,
- в инициализации
a
(это незаконно присвоить массивы в C) и
- , когда
a
является операндом оператора sizeof
.
Таким образом, sizeof a
дает вам N
sizeof(T)
.
Когда вы делаете sizeof(a-3)
, тип операнда sizeof
определяется выражением a-3
. Поскольку a
в a-3
используется в value context (т. Е. Ни один из трех контекстов выше), его тип является «указателем на int», а имя a
распадается на указатель на a[0]
. Таким образом, вычисление a-3
является неопределенным поведением, но поскольку sizeof
не оценивает его аргумент, a-3
используется только для определения типа операнда, поэтому код в порядке (см. Первую ссылку выше для более).
Из вышеизложенного sizeof(a-3)
эквивалентен sizeof(int *)
, что соответствует 4 на вашем компьютере.
«Преобразование» связано с оператором вычитания. Вы можете увидеть подобное, и, возможно, более удивительным, результат с оператором запятая:
printf("%zu\n", sizeof(1, a));
также напечатает sizeof(int *)
, из-за оператора запятая в результате a
привыкания в контексте значения.
Второй на самом деле печатает 'sizeof (int *)', а не 'sizeof (int)'. 'sizeof (int *)' просто бывает 4 на вашей платформе. – AnT
Кроме того, правильный способ печати значения 'size_t' (значение, возвращаемое' sizeof') с ''% zu'', если ваш компилятор поддерживает эту особенность C99. Если нет, лучше сделать бросок на «unsigned» или «unsigned long». –