Подтвердить что ты не робот

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

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

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

Почему -1 > sizeof(int) true?

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

Является ли этот стандартный компилятор С++?

4b9b3361

Ответ 1

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

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

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

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

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

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

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

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

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

В результате получается константа типа size_t

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

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

Ответ 2

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

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

Ответ 3

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

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

Ответ 4

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

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

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

Правило:

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

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

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