signed int x= -5;
unsigned int y=x;
каково значение y? и как?
signed int x= -5;
unsigned int y=x;
каково значение y? и как?
Это зависит от максимального значения 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.
Из стандарта C99:
6.3.1.3 Целочисленные и беззнаковые целые числа
- Когда значение с целым типом преобразуется в другой целочисленный тип кроме _Bool, если значение может быть представлено новым типом, оно не изменяется.
- В противном случае, если новый тип без знака, значение преобразуется на многократное добавление или вычитая одно больше максимального значения, которое может быть представлено в новом типе пока значение не окажется в диапазоне нового типа. 49)
49) Правила описывают арифметику по математическому значению, а не по значению данного типа выражения.
Итак, вы будете эффективно смотреть y = x + UINT_MAX + 1
.
Это просто означает, что представление twos-complement используется без изменений как целое число без знака, что делает это очень быстро на большинстве современных компьютеров, поскольку они используют двойное дополнение для целых чисел со знаком.
Значение y
равно UINT_MAX - 5 + 1
, то есть UINT_MAX - 4
.
При преобразовании знакового целочисленного значения в неподписанный тип значение уменьшается по модулю 2 ^ N, где N - число битов формирования значения в неподписанном типе. Это относится как к отрицательным, так и к положительным знаковым значениям.
Если вы конвертируете из подписанного типа в неподписанный тип того же размера, то это означает, что положительные значения подписей остаются неизменными (например, t23 > преобразуется в 5
), а отрицательные значения добавляются в MAX + 1
, где MAX
- максимальное значение неподписанного типа (-5
преобразуется в MAX + 1 - 5
).
Подписанные значения обычно хранятся как нечто, называемое два дополнения:
Два номера дополнений - это способ кодирования отрицательных чисел в обычные двоичные файлы, так что добавление все еще работает. Добавление -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;
у = 0xfffffffb это двоичное представление -5 (два дополнения)