Присваивание отрицательных чисел неподписанному int? - PullRequest
52 голосов
/ 02 марта 2011

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

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

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

Ответы [ 14 ]

61 голосов
/ 02 марта 2011

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

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

30 голосов
/ 02 марта 2011

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

Попробуйте

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

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

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

17 голосов
/ 02 марта 2011

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

6 голосов
/ 02 марта 2011

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

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

0000 0000 0000 1100 целое число без знака и целое число со знаком 12

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

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

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

Таким образом, причина, по которой вы не видите ожидаемого, заключается в том, что

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

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

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

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

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

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

unsigned int allBitsOn = -1;

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

1111 1111 1111 1111

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

4 голосов
/ 02 марта 2011
printf('%d', x); 

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

printf('%u', x);

Кроме того, он по-прежнему не будет печатать «12», это будет «4294967284».

3 голосов
/ 03 марта 2011

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

3 голосов
/ 02 марта 2011

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

2 голосов
/ 02 марта 2011

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

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

1 голос
/ 12 октября 2018

-12 в 16-битном 2-х формате.Сделайте так: if (x & 0x8000) {x = ~ x + 1;} Это преобразует число -ve комплимента 2 в эквивалентное число + ve.Удачи.

1 голос
/ 24 мая 2016

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...