Почему printf ("% d", ~ a);отображает -4, когда а равен 3? - PullRequest
0 голосов
/ 26 ноября 2018

Запуск следующей программы -4, в то время как ожидается 252:

unsigned char a=3;
printf ("%d", ~a);

Почему этот код не отображает 252?

Я также проверил следующие действия в соответствии с предлагаемым ответом:

printf ("%u", ~a);

отображает: 4294967292

printf ("%hu", ~a);

Отображает: 65532

Почему ~a не возвращает unsigned char, поскольку равно an unsigned char?

Мой вопрос не в том, что мне делать, чтобы отобразить 252?У меня вопрос почему 252 не отображается?

Ответы [ 3 ]

0 голосов
/ 26 ноября 2018

В дополнение к ответу @ Someprogrammerdude , здесь приведены соответствующие отрывки из Книги 1) :

Унарные арифметические операторы (§6.5.3.3 / 4)

Результат оператора ~ является побитовым дополнением его (повышен [ !! ] ) операнд (то есть каждый бит в результатеустанавливается в том и только в том случае, если соответствующий бит в преобразованном операнде не установлен). Целочисленные преобразования выполняются для операнда, и результат имеет продвинутый тип. Если продвигаемый тип является типом без знака, выражение ~ E эквивалентно максимальному значению, представляемому вэтот тип минус E .

Арифметические операнды - булевы, символы и целые числа (§6.3.1.1) :

  1. Каждый целочисленный тип имеет ранг целочисленного преобразования, определенный следующим образом:

    • Никакие два целочисленных типа со знаком не должны иметь одинаковый ранг, даже если они имеют одинаковое представление.
    • Ранг целого типа со знаком должен быть больше ранга любого целочисленного типа со знаком с меньшей точностью.
    • Ранг long long int должен быть больше, чем ранг long int , который должен быть больше ранга int , который должен быть больше ранга short int , который должен быть больше ранга подписанный символ .
    • Ранг любого целого типа без знака должен равняться рангу соответствующего целочисленного типа со знаком, если таковой имеется.
    • Ранг любого стандартного целочисленного типа должен быть больше ранга любогорасширенный целочисленный тип с той же шириной.
    • Ранг char должен равняться рангу знакового символа и без знака char .
    • Ранг _Bool должен быть меньше, чем ранг всех других стандартных целочисленных типов.
    • Ранг любого перечисляемого типа должен равняться рангу совместимого целочисленного типа (см. 6.7.2.2).
    • Ранг любого расширенного целочисленного типа со знаком относительно другого расширенного целочисленного типа со знаком с той же точностью определяется реализацией, но все же подчиняетсядругие правила определения ранга целочисленного преобразования.
    • Для всех целочисленных типов T1 , T2 и T3 , если T1 имеет более высокий ранг, чем T2 and T2 имеет более высокий ранг, чем T3 , тогда T1 имеет более высокий ранг, чем T3 .
  2. Следующее может использоваться в выражении везде, где может использоваться int или unsigned int :

    • Объект или выражение сцелочисленный тип, чей ранг целочисленного преобразования меньше или равен рангу int и unsigned int .
    • Битовое поле типа _Bool , int , подписано int или unsigned int . Если int может представлять все значения исходного типа, значение преобразуется в int ;в противном случае он преобразуется в без знака int .Они называются целочисленными продвижениями. 48) Все остальные типы не изменяются целочисленными продвижениями.
  3. Целочисленные продвижения сохраняют значение, включая знак.Как обсуждалось ранее, вопрос о том, рассматривается ли «простой» char как подписанный , определяется реализацией.

48) Применяются целочисленные повышениятолько: как часть обычных арифметических преобразований, в определенные выражения аргументов, в операнды унарных + , - и ~ операторов и обоим операндам операторов сдвига, указанным в соответствующих подпунктах.

Ваш вопрос:

Почему ~a не возвращает unsigned char, поскольку a является unsigned char?

Потому чтоприменяются целочисленные повышения.

unsigned char a = 3;
printf ("%d", ~a);

a - это unsigned char, тип с диапазоном, который может быть представлен int.Так что a получает звание int.Предполагая, что 32-битная ширина int с и дополняют два :

3 10 = 0000 0000 0000 0000 0000 0000 0000 0011 2 ~ 3 10 = 1111 1111 1111 1111 1111 1111 1111 1100 2 Результат, интерпретируемый как signed int, является отрицательным, поскольку установлен старший значащий бит, знаковый бит.Преобразовать в десятичное число:1111 1111 1111 1111 1111 1111 1111 1100 2 ¬ 0000 0000 0000 0000 0000 0000 0000 0011 2 + 0000 0000 0000 0000 0000 0000 0000 0001 2 ────────────────────────────0000 0000 0000 0000 0000 0000 0000 0100 2

0100 2 = 0 × 2 3 + 1 × 2 2 + 0 × 2 2 + 0 ×2 2 = 1 × 2 2 = 4 10 = −4 10 (с оригинальным знаком)

~> printf() печатает -4.

Чтобы получить желаемый результат 252 с вашим исходным кодом, который использует "%d" в качестве спецификатора формата, потребуется некоторое приведение:

unsigned char a = 3;
printf("%d\n", (int)((unsigned char) ~a));  // prints 252
//              ^^^   ^^^^^^^^^^^^^
//               |          cast the result of ~a back to unsigned char *)
//               |          to discard the bits > CHAR_BIT
//               cast the char back to int to agree with the format specifier 

*) Благодаря Чуксу, который заставил меня вспомнить, что char может быть signed!Приведение к (возможно signed) char даст неверный результат -4.

Чтобы получить тот же результат без приведения, вы можете использовать модификатор длины hh:

Функция fprintf (§7.19.6.1 / 7)

Модификаторы длины и их значения: чч Указывает, что следующие d , i , o , u , x или X спецификатор преобразования применяется к знаку char или unsigned char аргумент (аргумент будет повышен в соответствии с целочисленными повышениями, но его значение должно бытьпреобразуется в знаковый символ или неподписанный символ перед печатью);или что следующий указатель преобразования n применяется к указателю на аргумент со знаком char. [...]

unsigned char a = 3;
printf("%hhu\n", ~a);  // prints 252

Проблема с другими вашими попытками:

printf ("%u", ~a);

Отображение: 4294967292

printf ("%hu", ~a);

Отображение: 65532

С~a это int eger, неправильный тип для спецификатора формата u и

Функция fprintf (§7.19.6.1 / 9) :

Если спецификация преобразования недопустима, поведение не определено. 248) Если какой-либо аргумент имеет неправильный тип для соответствующей спецификации конвертации, поведение не определено.

1) ISO / IEC 9899 / Cor3: 2007 aka C99: TR3 или C99

0 голосов
/ 26 ноября 2018

Почему printf («% d», ~ a);отображать -4, когда a равно 3?
Почему ~a не возвращает unsigned char, поскольку a является unsigned char?

unsigned char a=3;

Потому что ~a является int -4, а не unsigned char 252 из-за целочисленных повышений .


Применение ~ вызывает целочисленных повышений из a до используется побитовое дополнение.

Если int может представлять все значения исходного типа ..., значение преобразуетсяна int;в противном случае он конвертируется в unsigned int.Они называются целочисленными акциями .

~3, учитывая общее целочисленное кодирование дополнения 2, равно -4.


на некоторых платформахunsigned char, int, unsigned имеют одинаковую битовую ширину.На этих исключительных платформах ~a может принимать значение, подобное FFFFFFFC (4294967292), так как вместо него повышается до unsigned.

0 голосов
/ 26 ноября 2018

Потому что ~a - это int, а не символ.Если вы хотите напечатать его как 8-разрядное целое число без знака, используйте формат "%hhu" как в

printf("%hhu\n", ~a);

Префикс hh для 8-битной части, u для неподписанного.

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

Из ссылки оцелочисленные обещания:

применяются целочисленные преобразования ... к операнду унарного побитового оператора ~

Ваша проблема представляет собой совокупность вопросов, которые обсуждались выше.

...