(-2147483648> 0) возвращает true в С++?
-2147483648 - это наименьшее целое число для целочисленного типа с 32 битами, но кажется, что оно будет переполняться в предложении if(...)
:
if (-2147483648 > 0)
std::cout << "true";
else
std::cout << "false";
В моем тестировании будет напечатано true
. Однако, если мы нажмем -2147483648 на целое число, результат будет другим:
if (int(-2147483648) > 0)
std::cout << "true";
else
std::cout << "false";
Откроется false
.
Я в замешательстве. Может ли кто-нибудь дать объяснение по этому поводу?
Обновление 02-05-2012:
Спасибо за ваши комментарии, в моем компиляторе размер int составляет 4 байта. Я использую VC для простого тестирования. Я изменил описание в своем вопросе.
В этом сообщении очень много ответов, AndreyT дал очень подробное объяснение того, как компилятор будет вести себя на таком входе и как это минимальное целое реализованы. qPCR4vir, с другой стороны, дал некоторые связанные "любопытства" и как целое число представлено. Настолько впечатляет!
Ответы
Ответ 1
-2147483648
не является "числом". Язык С++ не поддерживает отрицательные значения букв.
-2147483648
- фактически выражение: положительное буквальное значение 2147483648
с унарным оператором -
перед ним. Значение 2147483648
, по-видимому, слишком велико для положительной стороны диапазона int
на вашей платформе. Если тип long int
имел больший диапазон на вашей платформе, компилятор должен был бы автоматически предположить, что 2147483648
имеет тип long int
. (В С++ 11 компилятор также должен был бы учитывать тип long long int
.) Это заставит компилятор оценить -2147483648
в домене более крупного типа, и результат будет отрицательным, как и следовало ожидать.
Однако, по-видимому, в вашем случае диапазон long int
совпадает с диапазоном int
, и вообще нет целочисленного типа с большим диапазоном, чем int
на вашей платформе. Формально это означает, что положительная константа 2147483648
переполняет все доступные целые типы со знаком, что, в свою очередь, означает, что поведение вашей программы undefined. (Несколько странно, что спецификация языка выбирает поведение undefined в таких случаях вместо того, чтобы требовать диагностическое сообщение, но так, как оно есть.)
На практике, принимая во внимание, что поведение undefined, 2147483648
может интерпретироваться как некоторое отрицательное значение, зависящее от реализации, которое становится положительным после применения унарного -
к нему. В качестве альтернативы, некоторые реализации могут решить попытаться использовать неподписанные типы для представления значения (например, в C89/90 компиляторы должны были использовать unsigned long int
, но не на C99 или С++). Реализациям разрешено делать что-либо, поскольку поведение undefined в любом случае.
В качестве побочного примечания, именно поэтому константы типа INT_MIN
обычно определяются как
#define INT_MIN (-2147483647 - 1)
вместо кажущегося более простого
#define INT_MIN -2147483648
Последний не будет работать так, как предполагалось.
Ответ 2
Компилятор (VC2012) способствует достижению "минимальных" целых чисел, которые могут удерживать значения. В первом случае signed int
(и long int
) не может (до применения знака), но unsigned int
может: 2147483648
иметь unsigned int
???? тип.
Во втором вы нажимаете int
из unsigned
.
const bool i= (-2147483648 > 0) ; // --> true
предупреждение C4146: унарный оператор минус, примененный к неподписанному типу, результат все еще без знака
Здесь приведены "курьезы":
const bool b= (-2147483647 > 0) ; // false
const bool i= (-2147483648 > 0) ; // true : result still unsigned
const bool c= ( INT_MIN-1 > 0) ; // true :'-' int constant overflow
const bool f= ( 2147483647 > 0) ; // true
const bool g= ( 2147483648 > 0) ; // true
const bool d= ( INT_MAX+1 > 0) ; // false:'+' int constant overflow
const bool j= ( int(-2147483648)> 0) ; // false :
const bool h= ( int(2147483648) > 0) ; // false
const bool m= (-2147483648L > 0) ; // true
const bool o= (-2147483648LL > 0) ; // false
Стандарт С++ 11:
2.14.2 Целочисленные литералы [lex.icon]
...
Integer литерал представляет собой последовательность цифр, которая не имеет периода или экспоненциальная часть. Integer литерал может иметь префикс, который указывает его base и суффикс, который указывает его тип.
...
Тип целочисленного литерала является первым из соответствующего списка в котором может быть представлено его значение.
![enter image description here]()
Если целочисленный литерал не может быть представлен каким-либо типом в его списке и расширенный целочисленный тип (3.9.1) может представлять его значение, он может имеют расширенный целочисленный тип. Если все типы в списке для буквенный знак подписан, расширенный целочисленный тип должен быть подписан. Если все типы в списке для литерала являются неподписанными, расширенный целочисленный тип должен быть неподписанным. Если список содержит оба подписанные и неподписанные типы, расширенный целочисленный тип может быть подписан или без знака. Программа плохо сформирована, если одна из ее единиц перевода содержит целочисленный литерал, который не может быть представлен ни одним из разрешенных типов.
И это правила продвижения для целых чисел в стандарте.
4.5 Интегральные акции [conv.prom]
Значение целочисленного типа, отличного от bool
, char16_t
, char32_t
или wchar_t
, чей целочисленный ранг преобразования (4.13) меньше ранга int может быть преобразован в prvalue типа int
, если int
может представлять все значения типа источника; в противном случае исходное значение может быть преобразуется в prvalue типа unsigned int
.
Ответ 3
Короче говоря, 2147483648
переполняется до -2147483648
, а (-(-2147483648) > 0)
- true
.
Это, как выглядит 2147483648
в двоичном формате.
Кроме того, в случае подписанных двоичных вычислений наиболее значимым битом ( "MSB" ) является бит знака. Этот вопрос может помочь объяснить, почему.
Ответ 4
Потому что -2147483648
на самом деле 2147483648
с отрицанием (-
), примененным к нему, это не то, что вы ожидаете. Это фактически эквивалент этого псевдокода: operator -(2147483648)
Теперь, если ваш компилятор имеет sizeof(int)
, равный 4
, а CHAR_BIT
определяется как 8
, это сделало бы 2147483648
переполнением максимального значащего значения целого числа (2147483647
). Итак, каков максимальный плюс один? Позволяет работать с 4-битным, 2-х комплиментным целым.
Подождите! 8 переполняет целое число! Что мы делаем? Используйте его беззнаковое представление 1000
и интерпретируйте биты как целое число со знаком. Это представление оставляет нас при применении -8
отрицания дополнения 2s, приводящего к 8
, которое, как мы все знаем, больше, чем 0
.
Вот почему <limits.h>
(и <climits>
) обычно определяют INT_MIN
как ((-2147483647) - 1)
- так что максимальное знаковое целое число (0x7FFFFFFF
) отрицается (0x80000001
), затем уменьшается (0x80000000
).