1) You have specified width as %5x but there is a rule regarding width specifier in C. If the width of the number to be printed is more than the assigned width, the width specifier is ignored. So in the last column the number content cant be represented in the assigned width 5 so width limit has been ignored.Why width is greater than 5 i have explained in 3rd point. Now in 2nd point i tell %x vs unsigned char .
2) See friend you have declared variable 'n' as an unsigned char but you have used %x which is for unsigned hexadecimal int. So at the time of printing the value of n is promoted or technically you can say typecasted as an unsigned hexadecimal integer. It is not only in the case of unsigned char and %x. You should try dirrerent combinations on your compiler just like
int a=-5;
printf("%d %u",a,a);
now you will get -5 by %d and for %u you will get some other interpretaion dependent on compiler properties whether it is 16-bit or 32-bit.
now if you try
unsigned int a=-5;
printf("%d %u",a,a);
result will be still same as previous. in first case you write int a=5 and in the second case you write unsigned int =5 but result is dependent on the interpretation so this is like such.
This is about typecasting or you can say about interpretation by the compiler. when you say %x You yourself say to compiler that interpret it as a unsigned hexadecimal int. i hope its clear now, in case its not i suggest you to run little different programs and that too on many compilers. Programs like int x=7; printf("%f "x); etc etc .. you will surely get the point. Now i explain the out of the last column why its like fffffffe.
3) We consider the first run of the loop. here n=0x1. In a 32-bit compiler it will be represented in memory as 0000 0001 as char is provided 1 byte of memory.But afterwards when you typecast it as a unsigned hexadecimal integer the interpertation in a 32-bit compiler is 0000 0000 0000 0000 0000 0000 0000 0001 Well if you declare int n=1 or you declare unsigned int n=1 or you declare int n=0x1. the representation will be same. even if you use unsigned char n=1 the rightmost digit will be 1 and all others zero although the number of zeros may be less. Now in your looping statement by denoting %x you tell compiler to interpret the content as a unsigned hexadecimal int, so compiler provides it space as an hexadecimal and you do this opertion "~n" now by performing this operation the bit representation becomes like this 1111 1111 1111 1111 1111 1111 1111 1110. (caution-Remember that printf("%d",~n); case is different than printf("%d",n++); in the n++ case the value of variable in the memory gets updated too. but using printf("%d",~n) is similar using printf("%d",n+8).) So as per this new representaion of bits all bits are 1 except the rightmost. Now when it gets printed it gets printed like fffffffe. simple!
4)You have written " but it seems like it's being cast to a signed 32 bit value and sign extended by the %5x specifier." hmmm %x is not for signed hexadecimal int %x is for unsigned hexadecimal int so no point of assuming that minus sign got truncated.
5)In your progam you have used '~n' now just check different versions like this '-~n' or
'-n' . this is for experiment purpose.