sizeof ведет себя неожиданно

Рассмотрим следующий код:

  #include <stdio.h>
  int main(void)
  {
    int a[10];
    printf("%d",(int)sizeof(a)); //prints 10*sizeof(int) (40 on my compiler)
    printf("%d",(int)sizeof(a-3)); //prints sizeof(int) (4 on my compiler)

  }

я знаю это sizeof() является оператором времени компиляции, но я был удивлен, увидев вывод второго printf(), Что может быть причиной? Есть ли неявное преобразование аргумента sizeof() из типа массива в целочисленный тип?

4 ответа

Решение

sizeof оператор не оценивает свой аргумент, он только смотрит на тип своего операнда.

Допустим, у вас есть массив 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 используется в контексте значения (т. е. ни в одном из трех указанных выше контекстов), его типом является "указатель на int", а имя a распадается на указатель на a[0], Как таковой, расчет a-3 неопределенное поведение, но так как sizeof не оценивает свой аргумент, a-3 используется только для определения типа операнда, поэтому код в порядке (подробнее см. первую ссылку выше).

Из вышесказанного, sizeof(a-3) эквивалентно sizeof(int *)4 на вашем компьютере.

"Преобразование" происходит из-за оператора вычитания. Вы можете увидеть похожий и, возможно, более удивительный результат с запятой:

printf("%zu\n", sizeof(1, a));

также распечатает sizeof(int *)из-за оператора запятой, приводящего к a привыкнуть в контексте значения.

(a-3) имеет тип int*и печатает тебя sizeof(int*) который 4 на вашей платформе.

И обратите внимание, что sizeof() больше не является константой времени компиляции в C99 (из-за массивов переменной длины).

Нет, во втором случае аргумент интерпретируется как int* указатель, который также имеет размер 4 на вашем компьютере.

sizeof() возвращает размер типа, поэтому важен тип.

Это также не должно быть напечатано с %d, По крайней мере, явно приведите его к unsigned long или же unsigned long long и используйте соответствующий спецификатор формата. Когда я преподавал C, у меня был студент, который получил неправильный ответ, напечатав size_t с %d как ошибочно сказано в учебнике.

Тем не мение, a тип массива В C типы массивов переходят в типы указателей, если вы делаете с ними почти все или громко чихаете, поэтому почти все, что вы делаете для a даст тип указателя. Как вы узнали, добавление или вычитание числа будет затухать. (В конце концов, массив не может быть использован в арифметике, но указатель может.)

Другие вопросы по тегам