Почему unsigned int 0xFFFFFFFF равен int -1? - PullRequest
26 голосов
/ 08 декабря 2009

В C или C ++ говорится, что максимальное число, которое может содержать size_t (тип данных unsigned int), совпадает с приведением -1 к этому типу данных. например, см. Неверное значение для size_t

Почему?

Я имею в виду, (говоря о 32-битных целых). AFAIK старший значащий бит содержит знак в типе данных со знаком (то есть бит 0x80000000 для формирования отрицательного числа). тогда 1 равно 0x00000001 .. 0x7FFFFFFFF - наибольшее положительное число, которое может содержать тип данных int.

Тогда, AFAIK, двоичное представление -1 int должно быть 0x80000001 (возможно, я ошибаюсь). почему / как это двоичное значение преобразуется во что-то совершенно другое (0xFFFFFFFF) при преобразовании целых чисел в unsigned ?? или .. как можно сформировать двоичный код -1 из 0xFFFFFFFF?

Я не сомневаюсь, что в C: (((unsigned int) -1) == 0xFFFFFFFF или ((int) 0xFFFFFFFF) == -1 одинаково верно, чем 1 + 1 == 2, мне просто интересно, почему .

Ответы [ 6 ]

47 голосов
/ 08 декабря 2009

C и C ++ могут работать на разных архитектурах и типах машин. Следовательно, они могут иметь различные представления чисел: дополнение к двум, и дополнение к единице является наиболее распространенным. В общем, вы не должны полагаться на конкретное представление в вашей программе.

Для целочисленных типов без знака (size_t является одним из них) стандарт C (и, думаю, стандарт C ++ тоже) определяет точные правила переполнения. Короче говоря, если SIZE_MAX является максимальным значением типа size_t, то выражение

(size_t) (SIZE_MAX + 1)

гарантированно будет 0, и, следовательно, вы можете быть уверены, что (size_t) -1 равно SIZE_MAX. То же самое относится и к другим типам без знака.

Обратите внимание, что вышеизложенное верно:

  • для всех типов без знака,
  • , даже если базовый компьютер не представляет числа в дополнении к двум . В этом случае компилятор должен убедиться, что идентичность верна.

Кроме того, приведенное выше означает, что вы не можете полагаться на конкретные представления для подписанных типов.

Редактировать : Чтобы ответить на некоторые комментарии:

Допустим, у нас есть фрагмент кода вроде:

int i = -1;
long j = i;

В присвоении j есть преобразование типов. Предполагая, что int и long имеют разные размеры (большинство [все?] 64-битных систем), битовые структуры в ячейках памяти для i и j будут разными, потому что они имеют разные размеры , Компилятор гарантирует, что значения из i и j равны -1.

Аналогично, когда мы делаем:

size_t s = (size_t) -1

Идет преобразование типов. -1 имеет тип int. Он имеет битовую комбинацию, но это не имеет значения для этого примера, потому что когда преобразование в size_t происходит из-за преобразования, компилятор преобразует значение в соответствии с правилами для типа (size_t в данном случае). Таким образом, даже если int и size_t имеют разные размеры, стандарт гарантирует, что значение, сохраненное в s выше, будет максимальным значением, которое может принять size_t.

Если мы сделаем:

long j = LONG_MAX;
int i = j;

Если LONG_MAX больше INT_MAX, то значение в i определяется реализацией (C89, раздел 3.2.1.2).

26 голосов
/ 08 декабря 2009

Это называется дополнением к двум. Чтобы получить отрицательное число, инвертируйте все биты, затем добавьте 1. Итак, чтобы преобразовать 1 в -1, инвертируйте его в 0xFFFFFFFE, затем добавьте 1, чтобы сделать 0xFFFFFFFF.

Что касается того, почему это так, Википедия говорит:

Преимущество системы двойного дополнения состоит в том, что в схемах сложения и вычитания не требуется проверять знаки операндов, чтобы определить, прибавлять или вычитать. Это свойство делает систему более простой в реализации и способной легко обрабатывать более точную арифметику.

7 голосов
/ 08 декабря 2009

Ваш первый вопрос о том, почему (unsigned)-1 дает максимально возможное значение без знака, только случайно связан с дополнением до двух. Причина, по которой приведение -1 к типу без знака дает наибольшее возможное значение для этого типа, заключается в том, что стандарт говорит, что типы без знака «следуют законам арифметики по модулю 2 n , где n - количество битов в значении представление этого конкретного размера целого числа. "

Теперь для дополнения 2 представление наибольшего возможного значения без знака и -1 оказывается одинаковым - но даже если аппаратное обеспечение использует другое представление (например, дополнение 1 или знак / величина), преобразуя -1 в тип unsigned должен по-прежнему создавать максимально возможное значение для этого типа.

3 голосов
/ 08 декабря 2009

дополнение к двум очень хорошо для вычитания, как сложение :)

    11111110 (254 or -2)
   +00000001 (  1)
   ---------
    11111111 (255 or -1)

    11111111 (255 or -1) 
   +00000001 ( 1)
   ---------
   100000000 ( 0 + 256)
1 голос
/ 08 декабря 2009

То есть кодировка дополнения до двух .

Главный бонус заключается в том, что вы получаете одинаковую кодировку независимо от того, используете ли вы неподписанный или подписанный int. Если вы вычтете 1 из 0, целое число просто обернется. Следовательно, 1 меньше 0 равно 0xFFFFFFFF.

0 голосов
/ 24 июля 2015

Потому что битовый шаблон для int -1 - FFFFFFFF в шестнадцатеричном формате без знака. 11111111111111111111111111111111 двоичный без знака. Но в int первый бит показывает, является ли он отрицательным. Но в unsigned int первый бит - просто дополнительное число, потому что unsigned int не может быть отрицательным. Таким образом, дополнительный бит делает неподписанный int способным хранить большие числа. Как и в случае с неподписанным int, 11111111111111111111111111111111 (двоичный) или FFFFFFFF (шестнадцатеричный) является наибольшим числом, которое может хранить uint. Неподписанные целочисленные значения не рекомендуются, поскольку, если они становятся отрицательными, они переполняются и переходят к наибольшему числу.

...