Присвоение отрицательных чисел неподписанному int?

В языке программирования C unsigned int используется только для хранения положительных значений. Однако, когда я запускаю следующий код:

unsigned int x = -12;
printf("%d", x);

Выход по-прежнему -12. Я думал, что это должно было напечатать: 12, или я что-то не понимаю?

Ответ 1

-12 справа от вашего знака равенства устанавливается как целое число со знаком (возможно, 32 бита) и будет иметь шестнадцатеричное значение 0xFFFFFFF4. Компилятор генерирует код для перемещения этого знакового целого в ваше целое число без знака x, которое также является 32-битным объектом. Компилятор предполагает, что у вас есть только положительное значение справа от знака равенства, поэтому он просто перемещает все 32 бита в x. x теперь имеет значение 0xFFFFFFF4, которое 4294967284 интерпретируется как положительное число. Но формат printf %d говорит, что 32 бита должны интерпретироваться как целое число со знаком, поэтому вы получаете -12. Если вы использовали %u, он напечатал бы как 4294967284.

В любом случае вы не получите то, что ожидали, так как язык C "доверяет" писателю кода, чтобы просить "разумные" вещи. Это часто встречается в C. Если вы хотите присвоить значение x и не были уверены, что значение в правой части равенства было положительным, вы могли бы написать unsigned int x = abs(-12); и вынудили компилятор сгенерировать код, чтобы принять абсолютное значение целого числа со знаком, прежде чем переместить его в целое число без знака.

Ответ 2

Int не имеет значения, но вы сказали printf посмотреть на него как подписанный int.

Попробуйте

unsigned int x = -12; printf("%u", x);

Он не будет печатать "12", но будет печатать максимальное значение unsigned int минус 11.

Упражнение для читателя - выяснить, почему:)

Ответ 3

Передача% d в printf сообщает printf рассматривать аргумент как целое число со знаком, независимо от того, что вы действительно проходите. Используйте% u для печати как без знака.

Ответ 4

Все это связано с интерпретацией значения.

Если вы принимаете 16-битные подписанные и беззнаковые целые числа, то вот несколько примеров, которые не совсем правильны, но демонстрируют концепцию.

0000 0000 0000 1100 unsigned int и подписанное значение int 12

1000 0000 0000 1100 подписанное значение int -12 и большое целое без знака.

Для целых чисел со знаком бит слева является битом знака. 0 = положительный 1 = отрицательный

Для целых чисел без знака нет знакового бита. бит слева, позволяет вместо этого хранить большее число.

Таким образом, причина, по которой вы не видите то, что ожидаете, это то, что.

unsigned int x = -12, принимает -12 как целое число и сохраняет его в x. x не имеет знака, поэтому то, что было знаковым битом, теперь является частью ценности.

printf позволяет вам рассказать компилятору, как вы хотите отображать значение.

% d означает отображение его, как если бы это был подписанный int. % u означает отображать его так, как если бы он был беззнаковым int.

c позволяет вам делать такие вещи. Вы, программист, управляете.

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

возможно один полезный случай:

unsigned int allBitsOn = -1;

Это конкретное значение устанавливает все биты в 1

1111 1111 1111 1111

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

Ответ 5

printf('%d', x); 

Средство печатает целое число со знаком. Вы должны будете написать это вместо этого:

printf('%u', x);

Кроме того, он все равно не будет печатать "12", это будет "4294967284".

Ответ 6

Они сохраняют положительные значения. Но вы выводите (очень высокое) положительное значение как целое число со знаком, поэтому оно снова интерпретируется (в определенном для реализации варианте, я мог бы добавить).

Вместо этого используйте флаг формата "%u.

Ответ 7

В вашей программе есть поведение undefined, потому что вы передали неправильный тип printf (вы сказали, что собираетесь передать int, но вы передали unsigned int). Подумайте, что вам повезло, что "самая простая" вещь для реализации - это просто напечатать неверное значение, а не перейти к некоторому коду, который делает что-то вредное...

Ответ 8

То, что вам не хватает, заключается в том, что printf ( "% d", x) ожидает, что x будет подписана, поэтому, хотя вы назначаете -12 в x, он интерпретируется как 2 дополнения, которые были бы очень большим числом. Однако, когда вы передаете это действительно большое количество в printf, он интерпретирует его как подписанный, правильно переведя его обратно на -12.

Правильный синтаксис для печати unsigned в print f - "% u" - попробуйте это и посмотрите, что он делает!

Ответ 9

Назначение отрицательного значения для unsigned int не вычисляет абсолютное значение отрицательного значения: он интерпретирует как unsigned int двоичное представление отрицательного значения, то есть 4294967284 (2 ^ 32 - 12).

printf ( "% d" ) выполняет противоположную интерпретацию. Вот почему ваша программа отображает -12.

Ответ 10

Когда вы пытаетесь отобразить значение int, вы передаете его аргументу (int), а не аргументу (unsigned int), который вызывает его печать -12, а не 4294967284. Целые числа хранятся в шестнадцатеричном формате формат и -12 для int совпадает с 4294967284 для unsigned int в шестнадцатеричном формате.. Вот почему "% u" печатает нужное вам значение, а не "% d". Это зависит от вашего типа аргумента. УДАЧУЮТ!

Ответ 11

Когда компилятор неявно преобразует -12 в целое число без знака, базовое двоичное представление остается неизменным. Это преобразование чисто семантическое. Битовый знак двоичного целого числа является самым значимым битом целого числа без знака. Таким образом, когда printf обрабатывает целое число без знака как целое число со знаком с% ​​d, он увидит -12.

Ответ 12

В общем контексте, когда можно сохранить только положительные числа, отрицательные числа не сохраняются явно, но сохраняется их 2 дополнения. Таким же образом здесь 2 дополнения -12 будут сохранены в 'x', и вы используете %u для его получения.

Ответ 13

int и unsigned int используются для выделения количества байтов для сохранения значения больше.

Компилятор должен давать предупреждения о несоответствии подписки, но это действительно не влияет на биты в памяти, которые представляют значение -12.

% x,% d,% u etc сообщает компилятору, как прервать несколько бит при их печати.