C семантика относительно преобразования целых чисел определяется в терминах математических значений, а не в битах. Хорошо понимать, как значения представляются в виде битов, но при анализе выражений вам следует подумать о значениях.
В этом утверждении:
printf("Signed : %d\n",x);
signed char
x
автоматически повышается до int
. Поскольку x
равно -1, новый int
также имеет значение -1, а printf
печатает «-1».
В этом утверждении:
printf("Unsigned : %d\n",(unsigned)x);
signed char
x
автоматически повышается до int
. Значение по-прежнему -1. Затем приведение преобразует это в unsigned
. Правило для преобразования в unsigned
состоит в том, что UINT_MAX+1
добавляется или вычитается из значения по мере необходимости, чтобы привести его в диапазон unsigned
. В этом случае добавление UINT_MAX+1
к -1 один раз приводит к значению UINT_MAX
, которое находится в пределах диапазона. Таким образом, результат преобразования равен UINT_MAX
.
Однако это значение unsigned
затем передается в printf
для печати с преобразованием %d
. Это нарушает C 2018 7.21.6.1 9, в котором говорится, что поведение не определено, если типы не совпадают.
Это означает, что реализация C может делать что угодно. В вашем случае, кажется, что произошло:
- Значение
unsigned
UINT_MAX
представлено всеми одними битами.
-
printf
интерпретирует значение "все единичные биты" как int
.
- Ваша реализация использует два дополнения для
int
типов.
- В дополнении к двум объект со всеми одним битом представляет -1.
- Итак
printf
напечатано «-1».
Если вы использовали этот правильный код вместо:
printf("Unsigned : %u\n",(unsigned)x);
затем printf
выведет значение UINT_MAX
, что, вероятно, составляет 4 294 967 295, поэтому printf
выведет «4294967295».