Что произойдет, если я назначу отрицательное значение переменной без знака?

Мне было любопытно узнать, что произойдет, если я назначу отрицательное значение переменной без знака.

Код будет выглядеть примерно так.

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к этому беззнаковому целому числу.

Скомпилированный пример ссылки.

Другие вопросы по тегам