переполнение — (-2147483648 & gt; 0) возвращает true в C ++?

-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 с другой стороны, дал некоторые связанные «курьезы» и то, как представлены целые числа. Так впечатляет!

235

Решение

-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

Последний не будет работать как задумано.

384

Другие решения

Компилятор (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

Стандарт C ++ 11:

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,

43

Короче, 2147483648 переполняется на -2147483648, а также (-(-2147483648) > 0) является true,

это я показываю 2147483648 выглядит как в двоичном

Кроме того, в случае двоичных вычислений со знаком наиболее значимым битом («MSB») является знаковый бит. Этот вопрос может помочь объяснить почему.

7

Так как -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).

4
По вопросам рекламы [email protected]