Почему -1? Sizeof (int)? - PullRequest
17 голосов
/ 23 июня 2010

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

template<bool> class StaticAssert;
template<> class StaticAssert<true> {};
StaticAssert< (-1 < sizeof(int)) > xyz1; // Compile error
StaticAssert< (-1 > sizeof(int)) > xyz2; // OK

Почему -1 > sizeof(int) верно?

  1. Правда ли, что -1 повышен до unsigned(-1), а затем unsigned(-1) > sizeof(int).
  2. Правда ли, что -1 > sizeof(int) эквивалентно -1 > size_t(4), если sizeof (int) равно 4. Если это так, то почему -1 > size_t(4) неверно?

Соответствует ли стандарт C ++ стандарту?

Ответы [ 4 ]

14 голосов
/ 23 июня 2010

Ниже описано, как стандарт (ISO 14882) объясняет прерывание -1> sizeof (int)

Реляционный оператор `> 'определен в 5.9 (expr.rel / 2)

Обычные арифметические преобразования выполняются над операндами арифметического или перечислимого типа....

Обычные арифметические преобразования определены в 5 (expr / 9)

... Шаблон называется обычными арифметическими преобразованиями, которые определены следующим образом:

  • Если любой из операндов имеет тип long double, ...
  • В противном случае, если любой из операндов является dobule, ...
  • В противном случае, если любой из операндов является плавающим, ...
  • В противном случае интегральные продвижения выполняются для обоих операндов.
  • ...

Интегральные продвижения определены в 4.5 (конв.prom / 1)

r-значение типа char, знаковый char, unsigned char, short int или unsigned short int можно преобразовать в rvalue типа int, если int может представлять все значенияТип источника;в противном случае исходное значение r может быть преобразовано в значение типа unsigned int.

Результат sizeof определен в 5.3.3 (expr.sizeof / 6)

Результатом является константа типа size_t

size_t определена в стандарте C (ISO 9899), которая представляет собой целочисленный тип без знака .

Так что для -1 > sizeof(int),> запускает обычные арифметические преобразования.Обычное арифметическое преобразование преобразует -1 в беззнаковое целое, потому что int не может представлять все значения size_t.-1 становится очень большим числом в зависимости от платформы.Так что -1 > sizeof(int) это true.

14 голосов
/ 23 июня 2010

Поскольку неподписанный сильнее, чем подписанный и -1 преобразуется в значение без знака на size_t, то есть фактически -1 == 0xFFFFFFFF > 4

Вот как это должно работать в соответствии со стандартом C ++

4 голосов
/ 23 июня 2010

, поскольку -1 преобразуется в size_t, а это тип данных без знака - так что (size_t)-1 == 4294967295 (в 32-битной системе), который определенно больше 4

, если вы добавляете -Wall кНапример, в настройках gcc вы получаете предупреждение о том, что вы сравниваете тип данных со знаком и без знака

2 голосов
/ 09 декабря 2011

Все просто и грустно.В C / C ++:

  1. большую часть времени целочисленные типы без знака имеют семантику модульных целых чисел (они представляют классы эквивалентности)
  2. сравнения целочисленных типов без знака имеют семантику обычногоцелочисленное упорядочение, так что 1U < 2U (IOW 0U является наименьшим unsigned значением)
  3. sizeof имеет тип size_t
  4. size_t - целое число без знака
  5. Точка (1) подразумевает, что смешанные арифметические вычисления с участием целого числа со знаком и без знака выполняются в модульной арифметике без знака: это единственная возможность без нарушения правила «среднее без знака без модульности».Тривиально преобразовать целое число в эквивалентный класс целых чисел.(В то время как другой путь требует выбора целого числа для представления класса эквивалентности.)
  6. Точка (5) подразумевает, что -1 < 1U интерпретируется как unsigned(-1) < 1U, а unsigned(-1) = - 1U,и, очевидно, - 1U < 1U, поэтому -1 < 1U верно.
  7. Очки (1,3,4) означают, что sizeof something действует (в основном) как эквивалентный класс (!!!).
  8. Все это означает, что -1 < sizeof something

Вывод: это ошибка проектирования, унаследованная от C.

Правило:

Используйте только типы без знака для модульной арифметики, манипулирования битами (операторы &, |, ^, <<, >>, ~), манипулирования байтами (unsigned char означает «байт» в C /C ++) и символы (unsigned char означает символ в C / C ++).

Не используйте типы без знака для арифметики.

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

...