Почему sizeof (x ++) не увеличивает x? - PullRequest
490 голосов
/ 22 ноября 2011

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

#include <stdio.h>

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

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

4 and 5

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

Ответы [ 9 ]

516 голосов
/ 22 ноября 2011

Из C99 Standard (акцент мой)

6.5.3.4 / 2

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

183 голосов
/ 22 ноября 2011

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 в качестве вывода.

47 голосов
/ 22 ноября 2011

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

6.5.3.4:

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

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

33 голосов
/ 22 ноября 2011

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

(sizeof x)  //this also works
19 голосов
/ 24 февраля 2014

Примечание

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

Оригинал

За исключениемдля массивов переменной длины sizeof не оценивает свои аргументы.Это видно из черновика стандартного раздела C99 6.5.3.4 Оператор sizeof абзац 2 , который гласит:

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

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

sizeof( char[x++]  ) ;

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

sizeof( char[func()]  ) ;

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

Обратите внимание, массивы переменной длины включены в черновик стандарта C99 раздел 6.7.5.2 описатели массивов, параграф 4 :

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

Обновление

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

[...] Где выражение размера является частью операнда оператора sizeof и изменения значения размераВыражение не повлияет на результат оператора, не указано, будет ли вычислено выражение размера.

Например, в таком случае ( посмотреть вживую ):

sizeof( int (*)[x++] )
10 голосов
/ 23 ноября 2011

Поскольку операнд оператора 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:

10 голосов
/ 22 ноября 2011

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

0 голосов
/ 30 ноября 2018

sizeof выполняется во время компиляции, но x++ может оцениваться только во время выполнения.Чтобы решить эту проблему, стандарт C ++ предписывает, чтобы операнд sizeof не оценивался (за исключением VLA).Стандарт C гласит:

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

0 голосов
/ 22 января 2013

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

...