unsigned char aaa = -10;
Значение int
-10
будет преобразовано в unsigned char
путем многократного добавления UCHAR_MAX + 1
, пока результат не будет в диапазоне [0, UCHAR_MAX]
, Скорее всего, char
имеет 8 бит в вашей системе, что означает UCHAR_MAX = 2**8 - 1 = 255
. Так что -10 + UCHAR_MAX + 1
это 246
, это в пределах досягаемости. Так aaa = 246
.
unsigned int bbb = (unsigned int)-5;
-5
добавляется UINT_MAX + 1
, при условии, что int
имеет 32 бита, это приводит к bbb = 4294967291
.
unsigned int ccc = (unsigned int)20 + (unsigned int)bbb;
Целочисленное переполнение без знака "обернуть вокруг". Таким образом, 20 + 4294967291 = 4294967311
больше, чем UINT_MAX = 2**32 - 1 = 4294967295
. Поэтому мы вычитаем UINT_MAX+1
, пока не окажемся в диапазоне [0, UINT_MAX]
. Итак, 4294967311 - (UINT_MAX+1) = 15
.
printf("%d\n", aaa);
Скорее всего, код в порядке. Скорее всего, на вашей платформе unsigned char
повышается до int
перед передачей в аргумент функции variadi c. Для получения информации о рекламных акциях вы можете прочитать cppreference неявных преобразований . Поскольку %d
ожидает, что int
и unsigned char
повышены до int
, код в порядке. [1]
printf("%d\n", ccc);
Эта строка приводит к неопределенному поведению . ccc
имеет тип unsigned int
, а спецификатор формата %d
printf
ожидает signed int
. Поскольку в вашей платформе для представления чисел используется двоичное дополнение, в результате printf
интерпретирует биты как значение со знаком, которое в любом случае равно 15
.
[1]: теоретически существует возможность unsigned char
имеет столько же битов, сколько int
, поэтому unsigned char
будет повышен до unsigned int
вместо int
, что также приведет к неопределенному поведению.