Почему sizeof (x ++) не увеличивает x?

Вот код, скомпилированный в dev c ++ windows:

#include  int main() { int x = 5; printf("%d and ", sizeof(x++)); // note 1 printf("%d\n", x); // note 2 return 0; } 

Я ожидаю, что x будет 6 после выполнения примечания 1 . Однако выход:

 4 and 5 

Может ли кто-нибудь объяснить, почему x не увеличивается после примечания 1 ?

Из стандарта C99 (акцент мой)

6.5.3.4/2

Оператор sizeof дает размер (в байтах) своего операнда, который может быть выражением или именем в скобках типа. Размер определяется по типу операнда. Результат – целое число. Если тип операнда – тип массива переменной длины, то операнд оценивается; в противном случае операнд не оценивается, а результат является целочисленной константой.

sizeof – это оператор времени компиляции, поэтому во время компиляции sizeof и его операнд заменяются значением результата. Операнд не оценивается (кроме случаев, когда он является массивом переменной длины); имеет значение только тип результата.

 short func(short x) { // this function never gets called !! printf("%d", x); // this print never happens return x; } int main() { printf("%d", sizeof(func(3))); // all that matters to sizeof is the // return type of the function. return 0; } 

Вывод:

 2 

так как short занимает 2 байта на моей машине.

Изменение возвращаемого типа функции в double :

 double func(short x) { // rest all same 

даст 8 качестве вывода.

sizeof(foo) действительно пытается найти размер выражения во время компиляции:

6.5.3.4:

Оператор sizeof дает размер (в байтах) своего операнда, который может быть выражением или именем в скобках типа. Размер определяется по типу операнда. Результат – целое число. Если тип операнда – тип массива переменной длины, то операнд оценивается; в противном случае операнд не оценивается, а результат является целочисленной константой.

Короче: массивы переменной длины, выполняемые во время выполнения. (Примечание. Массивы переменной длины – это определенная функция, а не массивы, выделенные с помощью malloc(3) .) В противном случае вычисляется только тип выражения, а во время компиляции.

sizeof является встроенным оператором компиляции и не является функцией. Это становится очень ясным в тех случаях, когда вы можете использовать его без круглых скобок:

 (sizeof x) //this also works 

Заметка

Этот ответ был объединен из дубликата, что объясняет позднюю дату.

оригинал

За исключением массивов переменной длины sizeof не оценивает свои аргументы. Мы можем видеть это из проекта стандартного раздела C99 6.5.3.4 Оператор sizeof оператора, который гласит:

Оператор sizeof дает размер (в байтах) своего операнда, который может быть выражением или именем в скобках типа. Размер определяется по типу операнда. Результат – целое число. Если тип операнда – тип массива переменной длины, то операнд оценивается; в противном случае операнд не оценивается, а результат является целочисленной константой.

Комментарий ( теперь удаленный ) спросил, будет ли что-то подобное оцениваться во время выполнения:

 sizeof( char[x++] ) ; 

и действительно, было бы так, что-то вроде этого тоже будет работать ( см. их обоих ):

 sizeof( char[func()] ) ; 

поскольку они представляют собой массивы переменной длины. Хотя, я не вижу много практического использования ни в одном.

Примечание. Массивы переменной длины описаны в стандартном разделе проекта C99. 6.7.5.2 Объявление декларатора массива, пункт 4 :

[…] Если размер представляет собой целочисленное константное выражение, а тип элемента имеет известный постоянный размер, тип массива не является массивом переменной длины; в противном случае тип массива представляет собой тип массива переменной длины.

Обновить

В C11 ответ изменяется для случая VLA, в некоторых случаях неопределено, оценивается ли выражение размера или нет. Из раздела 6.7.6.2 массива, которые гласят:

[…] Если выражение размера является частью операнда оператора sizeof и изменение значения выражения размера не повлияет на результат оператора, то не определено, оценивается ли выражение размера.

Например, в таком случае ( см. Его в прямом эфире ):

 sizeof( int (*)[x++] ) 

Поскольку операнд оператора sizeof не оценивается, вы можете сделать это:

 int f(); //no definition, which means we cannot call it int main(void) { printf("%d", sizeof(f()) ); //no linker error return 0; } 

Демо-версия: http://ideone.com/S8e2Y

То есть вам не нужно определять функцию f если она используется только в sizeof . Этот метод в основном используется в метапрограммировании шаблонов C ++, так как даже в C ++ операнд sizeof не оценивается.

Почему это работает? Он работает, потому что оператор sizeof не работает по значению , а работает по типу выражения. Поэтому, когда вы пишете sizeof(f()) , он работает с типом выражения f() , и это не что иное, как возвращаемый тип функции f . Тип возврата всегда один и тот же, независимо от того, какое значение возвращает функция, если оно действительно выполняется.

В C ++ вы можете даже это:

 struct A { A(); //no definition, which means we cannot create instance! int f(); //no definition, which means we cannot call it }; int main() { std::cout << sizeof(A().f())<< std::endl; return 0; } 

Но похоже, что в sizeof я сначала создаю экземпляр A , написав A() , а затем вызываю функцию f в экземпляре, написав A().f() , но такого не происходит.

Демо: http://ideone.com/egPMi

Вот еще одна тема, которая объясняет некоторые другие интересные свойства sizeof :

  • sizeof принимает два аргумента

Выполнение не может произойти во время компиляции. Так что ++i / i++ не произойдет. Также sizeof(foo()) не выполняет функцию, а возвращает правильный тип.

sizeof() дает размер только типа данных, он не оценивает внутренние элементы.

  • Использование sizeof с динамически распределенным массивом
  • Является ли разыменование нулевого указателя действительным в операции sizeof
  • Размер массивов и указателей
  • Является ли размер структуры требуемым, чтобы быть точным кратным выравниванию этой структуры?
  • Поведение sizeof для массивов переменной длины (только C)
  • Почему sizeof считается оператором?
  • Не оценивает ли выражение, к которому применяется значение sizeof, делает его законным для разыменования нулевого или недопустимого указателя внутри sizeof в C ++?
  • Оператор sizeof () в if-statement
  • c ++ sizeof () classа с функциями
  • Использование sizeof () в памяти malloc'd
  • sizeof union в C / C ++
  • Interesting Posts

    Преобразование между java.time.LocalDateTime и java.util.Date

    Потребность в предсказуемом случайном генераторе

    Как создать круговой ProgressBar в android?

    Как проверить, включено ли хотя бы одно из нескольких полей ввода?

    WinXP: разница между Log Off и Restart

    Изменение размера UI-изображений, снятых с камеры, также приводит к вращению UI-образа?

    Wake Android Device up

    Огромная разница в производительности (на 26 раз быстрее) при компиляции для 32 и 64 бит

    Ошибка D: \ недоступна. В доступе отказано

    Как написать таймер в Objective-C?

    Как закрыть приложение Java Swing из кода

    Как подсчитать ячейки в диапазоне со значением меньше, чем другая ячейка в excel?

    Если я использую дискретный графический процессор с Sandy Bridge, будет ли GPU Sandy Bridge стоять без дела и полностью потеряться?

    Java Swing: как я могу реализовать экран входа в систему, прежде чем показывать JFrame?

    Изменить язык ввода клавиатуры

    Давайте будем гением компьютера.