(-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 intlong 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).