Почему -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)
является ложным?
Является ли этот стандартный компилятор С++?
Ответы
Ответ 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/С++).
Не используйте беззнаковые типы для выполнения арифметики.
Если функция ожидает целочисленное значение, которое никогда не должно быть отрицательным, возьмите целое число со знаком и, возможно, проверьте функцию, что значение находится в диапазоне.