Что произойдет, если я назначу отрицательное значение переменной без знака?
Мне было любопытно узнать, что произойдет, если я назначу отрицательное значение переменной без знака.
Код будет выглядеть примерно так.
unsigned int nVal = 0;
nVal = -5;
Это не дало мне никакой ошибки компилятора. Когда я запустил программу nVal
было присвоено странное значение! Может ли быть так, что значение дополнения некоторых 2 присваивается nVal
?
7 ответов
Для официального ответа - раздел 4.7 conv.integral
"Если тип назначения не имеет знака, полученное значение является целочисленным с наименьшим числом без знака, соответствующим исходному целому числу (по модулю 2n, где
n
количество битов, используемых для представления типа без знака). [Примечание: в представлении дополнения до двух это преобразование является концептуальным, и в битовой комбинации нет изменений (если нет усечения). —Конечная записка]
По сути, это означает, что если базовая архитектура хранится в методе, который не является дополнением к двум (таким как знаковая величина или дополнение к одному), то преобразование в неподписанное должно вести себя так, как если бы это было дополнение к двум.
Это назначит битовую комбинацию, представляющую -5 (в дополнении 2) для беззнакового целого. Что будет большим значением без знака. Для 32-битных целых это будет 2^32 - 5 или 4294967291
Он будет отображаться как положительное целое число значения max целое число без знака - 4 (значение зависит от архитектуры компьютера и компилятора).
КСТАТИ
Вы можете проверить это, написав простую программу типа "привет мир" на C++ и убедитесь сами
Вы правы, целое число со знаком хранится в форме дополнения 2, а целое число без знака хранится в двоичном представлении без знака. C (и C++) не различают эти два, поэтому значение, которое вы в итоге получите, является просто беззнаковым двоичным значением двоичного представления дополнения 2.
Да, ты прав. Фактическое назначенное значение похоже на все установленные биты, кроме третьего. -1 - все установленные биты (hex: 0xFFFFFFFF), -2 - все биты, кроме первого и так далее. Вероятно, вы увидите шестнадцатеричное значение 0xFFFFFFFB, которое в десятичном формате соответствует 4294967291.
Когда вы присваиваете отрицательное значение беззнаковой переменной, она использует метод дополнения 2 для ее обработки, и в этом методе он переворачивает все 0 на 1 и все 1 на 0, а затем добавляет к нему 1. В вашем случае вы имеете дело с int, который имеет 4 байта (32 бита), поэтому он пытается использовать метод дополнения 2 для 32-битного числа, что приводит к переворачиванию более высокого бита. Например:
┌─[student@pc]─[~]
└──╼ $pcalc 0y00000000000000000000000000000101 # 5 in binary
5 0x5 0y101
┌─[student@pc]─[~]
└──╼ $pcalc 0y11111111111111111111111111111010 # flip all bits
4294967290 0xfffffffa 0y11111111111111111111111111111010
┌─[student@pc]─[~]
└──╼ $pcalc 0y11111111111111111111111111111010 + 1 # add 1 to that flipped binarry
4294967291 0xfffffffb 0y11111111111111111111111111111011
В Windows и Ubuntu Linux, которые я проверил, присваивая любое отрицательное число (не только-1
) к целому числу без знака в C и C++ приводит к присвоению значенияUINT_MAX
к этому беззнаковому целому числу.
Скомпилированный пример ссылки.