Возможный дубликат:
Что произойдет, если я назначу отрицательное значение переменной без знака?
Я новичок в C ++, и я хочу знать, как использовать неподписанные типы. Для unsigned int
типа, я знаю, что он может принимать значения от 0 до 4294967296. но когда я хочу инициализировать тип без знака int следующим образом:
unsigned int x = -10;
cout << x;
Выход выглядит как 4294967286
Получил это output = max value - 10
, Итак, я хочу узнать, что происходит в памяти? Какие процессы выполняются, пока продолжается этот расчет? Спасибо за ваши ответы.
Вы сталкиваетесь с изменением поведения.
Типы без знака являются циклическими (с другой стороны, типы со знаком могут быть или не быть циклическими, но это неопределенное поведение, на которое не следует полагаться). То есть на единицу меньше минимально возможного значения — максимально возможное значение. Вы можете продемонстрировать это самостоятельно с помощью следующего фрагмента:
int main()
{
unsigned int x = 5;
for (int i = 0; i < 10; ++i) cout << x-- << endl;
return 0;
}
Вы заметите, что после достижения нуля значение x переходит к 2 ^ 32-1, максимально представительному значению. Вычитание дальнейших действий, как ожидалось.
Когда вы вычитаете 1 из 0 без знака, битовая комбинация изменяется следующим образом:
0000 0000 0000 0000 0000 0000 0000 0000 // before (0)
1111 1111 1111 1111 1111 1111 1111 1111 // after (2^32 - 1)
С числами без знака отрицательные числа обрабатываются как положительные числа, вычтенные из нуля. Так (unsigned int) -10
будет равно ((unsigned int) 0) - ((unsigned int) 10)
,
Мне нравится думать о нем как о беззнаковом int, представляющем собой младшие 32 бита произвольного значения с более высокой точностью. Как это:
v imaginary high order bit
1 0000 0000 0000 0000 0000 0000 0000 0000 // before (2^32)
0 1111 1111 1111 1111 1111 1111 1111 1111 // after (2^32 - 1)
Поведение unsigned int в этих случаях переполнения точно такое же, как и поведение младших 8 битов unsigned int, когда вы вычитаете 1 из 256. Имеет больше смысла смотреть на unsigned char (1 байт) следующим образом: потому что значения 0 и 256 равны, если приведено unsigned char
, поскольку ограниченная точность отбрасывает лишние биты.
0 0000 0000 0000 0000 0000 0001 0000 0000 // before (256)
0 0000 0000 0000 0000 0000 0000 1111 1111 // before (255)
Как уже отмечали другие, это называется модульной арифметикой. Использование значений более высокой точности, чтобы помочь визуализировать переходы, сделанные при обтекании, работает, потому что вы маскируете биты старшего разряда. Неважно, что это было, так что это может быть что угодно, его просто отбрасывают. Целые числа — это значения модуля 2 ^ 32, поэтому любые кратные 2 ^ 32 равны нулю в пространстве целого числа. Вот почему я могу сойти с ума, притворяясь, что на конце есть лишняя часть.
Операции модуля имеют свой собственный выделенный оператор на тот случай, если вам нужно вычислить их для чисел, отличных от 2 ^ 32, в ваших программах, как используется в этом операторе:
int forty_mod_twelve = 40 % 12;
// value is 4: 4 + n * 12 == 40 for some whole number n
Операции модуля на степенях двух (например, 2 ^ 32) упрощают непосредственно для маскирования старших битов, и если вы возьмете 64-битное целое число и вычислите его по модулю 2 ^ 32, значение будет точно таким же, как если бы вы его преобразовали без знака Int.
01011010 01011100 10000001 00001101 11111111 11111111 11111111 11111111 // before
00000000 00000000 00000000 00000000 11111111 11111111 11111111 11111111 // after
Программисты любят использовать это свойство для ускорения программ, потому что легко отрубить некоторое количество битов, но выполнить операцию модуля намного сложнее (это примерно так же сложно, как выполнить деление).
Имеет ли это смысл?
Это включает в себя стандартные интегральные преобразования. Вот применимое правило. Начнем с типа буквального 10
:
2.14.2 Целочисленные литералы [lex.icon]
Целочисленный литерал — это последовательность цифр, которая не имеет периода или части экспоненты. Целочисленный литерал может иметь
префикс, указывающий его базу и суффикс, указывающий его тип. Лексически первая цифра последовательности
из цифр является наиболее значимым. Десятичный целочисленный литерал (основание десять) начинается с цифры, отличной от0
а также
состоит из последовательности десятичных цифр. Восьмеричный целочисленный литерал (основание восемь) начинается с цифры0
а также
состоит из последовательности восьмеричных цифр. Шестнадцатеричный целочисленный литерал (основание шестнадцать) начинается с0x
или же0X
а также
состоит из последовательности шестнадцатеричных цифр, которые включают в себя десятичные цифры и буквыa
черезf
а такжеA
черезF
с десятичными значениями от десяти до пятнадцати. [Пример: число двенадцать может быть написано12
,014
, или же0XC
, — конец примера]Тип целочисленного литерала является первым из соответствующего списка в таблице 6, в котором его значение может быть
представлял.
Таблица следует, первый тип int
и это подходит. Таким образом, тип литерала int
,
Применяется унарный минус, который не меняет тип. Затем применяется следующее правило:
4.7 Интегральные преобразования [conv.integral]
Значение типа целого может быть преобразовано в значение другого целого типа. Значение типа перечисления с незаданной областью может быть преобразовано в значение типа целого числа.
Если тип назначения является беззнаковым, полученное значение является наименьшим целым числом без знака, соответствующим исходному целому числу (по модулю 2N где n — количество битов, используемых для представления типа без знака). [Примечание: в представлении дополнения до двух это преобразование является концептуальным, и в битовой комбинации нет изменений (если нет усечения). — конец примечания]
Вместо того, чтобы печатать значение таким, как есть, выведите его в шестнадцатеричном формате (извините, я забыл, как это сделать с помощью cout, но я знаю, что это возможно). Вы увидите, что представление одинаково для обоих значений.
В вашем контексте целое число составляет 32 бита (это не всегда так). При использовании целого числа со знаком наиболее значимым битом является знак, а не часть значения. При использовании целого числа без знака старший значащий бит является частью значения.