-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 с другой стороны, дал некоторые связанные «курьезы» и то, как представлены целые числа. Так впечатляет!
-2147483648
это не «число». Язык C ++ не поддерживает отрицательные литеральные значения.
-2147483648
на самом деле выражение: положительное буквальное значение 2147483648
с одинарным -
оператор перед ним. Значение 2147483648
по-видимому, слишком велик для положительной стороны int
Диапазон на вашей платформе. Если тип long int
Если бы на вашей платформе был больший диапазон, компилятор должен автоматически предполагать, что 2147483648
имеет long int
тип. (В C ++ 11 компилятор также должен учитывать long long int
типа.) Это сделает компилятор для оценки -2147483648
в области большего типа, и результат будет отрицательным, как и следовало ожидать.
Однако, по-видимому, в вашем случае диапазон long int
такой же, как диапазон int
и вообще нет целочисленного типа с большим диапазоном, чем int
на вашей платформе. Это формально означает, что положительная постоянная 2147483648
переполняет все доступные целые типы со знаком, что, в свою очередь, означает, что поведение вашей программы не определено. (Немного странно, что спецификация языка в таких случаях выбирает неопределенное поведение, вместо того, чтобы требовать диагностическое сообщение, но это так.)
На практике, принимая во внимание, что поведение не определено, 2147483648
может интерпретироваться как некоторое зависящее от реализации отрицательное значение, которое становится положительным после того, как -
применяется к нему. Альтернативно, некоторые реализации могут решить попытаться использовать неподписанные типы для представления значения (например, в C89 / 90 компиляторы должны были использовать unsigned long int
, но не в C99 или C ++). Реализациям разрешено делать что угодно, поскольку поведение в любом случае не определено.
В качестве примечания, это причина, по которой такие константы, как INT_MIN
обычно определяются как
#define INT_MIN (-2147483647 - 1)
вместо, казалось бы, более простой
#define INT_MIN -2147483648
Последний не будет работать как задумано.
Компилятор (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
2.14.2 Целочисленные литералы [lex.icon]
…
Целочисленный литерал — это последовательность цифр, которая не имеет периода или
экспонентная часть. Целочисленный литерал может иметь префикс, который определяет его
база и суффикс, который определяет его тип.
…
Тип целочисленного литерала является первым из соответствующего списка
в котором его значение может быть представлено.
Если целочисленный литерал не может быть представлен ни одним типом в его списке
и расширенный целочисленный тип (3.9.1) может представлять его значение, он может
иметь расширенный целочисленный тип. Если все типы в списке для
литерал подписан, расширенный целочисленный тип должен быть подписан. Если
все типы в списке для литерала не подписаны,
расширенный целочисленный тип должен быть без знака. Если список содержит оба
со знаком и без знака, расширенный целочисленный тип может быть подписан или
без знака. Программа плохо сформирована, если один из ее модулей перевода
содержит целочисленный литерал, который не может быть представлен ни одним из
разрешенные типы.
И это правила продвижения для целых чисел в стандарте.
4.5 Интегральные акции [Conv.prom]
Значение типа integer, отличного от
bool
,char16_t
,char32_t
, или же
wchar_t
чей ранг целочисленного преобразования (4.13) меньше, чем ранг
int может быть преобразовано в тип значенияint
еслиint
может представлять все
значения типа источника; в противном случае исходное значение может быть
преобразуется в значение типаunsigned int
,
Короче, 2147483648
переполняется на -2147483648
, а также (-(-2147483648) > 0)
является true
,
это я показываю 2147483648
выглядит как в двоичном
Кроме того, в случае двоичных вычислений со знаком наиболее значимым битом («MSB») является знаковый бит. Этот вопрос может помочь объяснить почему.
Так как -2147483648
на самом деле 2147483648
с отрицанием (-
) применительно к нему, число не то, что вы ожидаете. На самом деле это эквивалент этого псевдокода: operator -(2147483648)
Теперь, если ваш компилятор sizeof(int)
равно 4
а также CHAR_BIT
определяется как 8
что бы сделать 2147483648
переполнить максимальное целое значение со знаком (2147483647
). Так какой же максимум плюс один? Давайте разберемся с 4-битным целым числом комплимента 2s.
Подождите! 8 переполняет целое число! Что мы делаем? Используйте свое беззнаковое представление 1000
и интерпретировать биты как целое число со знаком. Это представление оставляет нас с -8
применяется отрицание дополнения 2s, что приводит к 8
что, как мы все знаем, больше 0
,
Вот почему <limits.h>
(а также <climits>
) обычно определяют INT_MIN
как ((-2147483647) - 1)
— так что максимальное целое число со знаком (0x7FFFFFFF
) отрицается (0x80000001
), затем уменьшается (0x80000000
).