Неподписанные и подписанные значения в C (каков результат)

signed int x= -5;
unsigned int y=x;

каково значение y? и как?

Ответ 1

Это зависит от максимального значения unsigned int. Как правило, a unsigned int имеет длину 32 бит, поэтому UINT_MAX составляет 2 32 & minus; 1. Стандарт C (раздел 6.3.1.3/2) требует подписанного & беззнаковое преобразование должно выполняться как

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

Таким образом, y = x + ((2 32 & minus; 1) + 1) = 2 32 & minus; 5 = 4294967291.


В платформе 2 дополнение, которая в настоящее время реализуется большинством реализаций, y также совпадает с представлением 2 .

-5 = ~ 5 + 1 = 0xFFFFFFFA + 1 = 0xFFFFFFFB = 4294967291.

Ответ 2

Из стандарта C99:

6.3.1.3 Целочисленные и беззнаковые целые числа

  • Когда значение с целым типом преобразуется в другой целочисленный тип кроме _Bool, если значение может быть представлено новым типом, оно не изменяется.
  • В противном случае, если новый тип без знака, значение преобразуется на многократное добавление или вычитая одно больше максимального значения, которое может быть представлено в новом типе пока значение не окажется в диапазоне нового типа. 49)

49) Правила описывают арифметику по математическому значению, а не по значению данного типа выражения.

Итак, вы будете эффективно смотреть y = x + UINT_MAX + 1.

Это просто означает, что представление twos-complement используется без изменений как целое число без знака, что делает это очень быстро на большинстве современных компьютеров, поскольку они используют двойное дополнение для целых чисел со знаком.

Ответ 3

Значение y равно UINT_MAX - 5 + 1, то есть UINT_MAX - 4.

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

Если вы конвертируете из подписанного типа в неподписанный тип того же размера, то это означает, что положительные значения подписей остаются неизменными (например, t23 > преобразуется в 5), а отрицательные значения добавляются в MAX + 1, где MAX - максимальное значение неподписанного типа (-5 преобразуется в MAX + 1 - 5).

Ответ 4

Подписанные значения обычно хранятся как нечто, называемое два дополнения:

Два номера дополнений - это способ кодирования отрицательных чисел в обычные двоичные файлы, так что добавление все еще работает. Добавление -1 + 1 должно равняться 0, но обычное добавление дает результат 2 или -2, если операция не требует особого внимания знакового бита и вместо этого выполняет вычитание. Два дополнительных результата приводят к правильной сумме без этого дополнительного шага.

Это означает, что фактическое представление чисел -5 и 4294967291 в памяти (для 32-битного слова) идентично, например: 0xFFFFFFFB или 0b11111111111111111111111111111011. Поэтому, когда вы делаете:

unsigned int y = x;

Содержимое x копируется дословно, то есть побитовое значение в y. Это означает, что если вы проверите необработанные значения в памяти x и y, они будут идентичны. Однако если вы выполните:

unsigned long long y1 = x;

значение x будет расширено знака перед преобразованием в unsigned long long. В общем случае, когда длинный длинный 64 бит, это означает, что y1 равно 0xFFFFFFFFFFFFFFFB.

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

unsigned int z = y + 5;
long long z1 = (long long)x + 5; // sign extended since x is signed
long long z2 = (long long)y + 5; // not sign extended since y is unsigned

z и z1 будет равно 0, но z2 не будет. Это можно устранить, добавив значение, подписанное до его расширения:

long long z3 = (long long)(signed int)y + 5;

или аналогично, если вы не хотите расширения знака:

long long z4 = (long long)(unsigned int)x;

Ответ 5

у = 0xfffffffb это двоичное представление -5 (два дополнения)