Результат ~a имеет тип int, и вычисляется обращением битов после превращения a в int (integer promotions, так как int может представить все значения unsigned char, если не рассматривать редкий случай когда UCHAR_MAX > INT_MAX). В с11 (n1570):
The result of the ~ operator is the bitwise complement of its (promoted) operand (that is,
each bit in the result is set if and only if the corresponding bit in the converted operand is
not set). The integer promotions are performed on the operand, and the result has the
promoted type. If the promoted type is an unsigned type, the expression ~E is equivalent
to the maximum value representable in that type minus E
К примеру, на одной из возможных реализаций:
(~a) -> ~(FF) -> ~(00 00 00 FF) -> FF FF FF 00 = -256
Затем %u интерпретирует int как unsigned int, поэтому для примера выше: printf() получает -256 (FF FF FF 00) и выводит 4294967040 (34 32 39...).
0 вы получите, если (~a) назад в unsigned char превратить:
unsigned char b = ~a;
в этом случае -256 в ноль превращается (§6.3.1.3/2) так как вычисления по модулю UCHAR_MAX+1 происходят (UCHAR_MAX=255 здесь). printf("%u", b) выведет 0.
Аналогично, в случае с %hhu: printf() получает int (FF FF FF 00) и интерпретирует его как unsigned char для печати:
#include <stdio.h>
int main(void) {
unsigned char a = 0xff, b = ~a;
printf("a=%d b=%d ~a=%d\n", a, b, ~a);
printf("a=%u b=%u ~a=%u\n", a, b, ~a);
printf("a=%hhu b=%hhu ~a=%hhu\n", a, b, ~a);
}
Результат
a=255 b=0 ~a=-256
a=255 b=0 ~a=4294967040
a=255 b=0 ~a=0
unsigned charподвергается целочисленному продвижению (integral promotion) и преобразуется либо вint, либо вunsigned int(это в том случае, еслиintне может представить все значенияunsigned char). Таким образом, при, например, 8-битномunsigned charи 32-битномintкажется, что происходит инверсия последовательности битов:11111111, а на самом деле происходит инверсия такой последовательности битов:00000000 00000000 00000000 11111111. – wololo Dec 09 '17 at 15:0711111111 11111111 11111111 00000000и именно эта последовательность битов и передаётся в функциюprintf. А за счёт спецификатора типа%uфункцияprintfинтерпретирует данную последовательность битов какunsigned int, т.е. как числовое значение4294967040. – wololo Dec 09 '17 at 15:07