sizeof ведет себя неожиданно - PullRequest
12 голосов
/ 05 февраля 2010

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

  #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 ]

30 голосов
/ 05 февраля 2010

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

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

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

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

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

5 голосов
/ 05 февраля 2010

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

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

1 голос
/ 05 февраля 2010

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

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

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

1 голос
/ 05 февраля 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...