http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53369
Andrew Pinski <pinskia at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|UNCONFIRMED |RESOLVED Resolution| |INVALID --- Comment #3 from Andrew Pinski <pinskia at gcc dot gnu.org> 2012-05-16 00:11:53 UTC --- signed char a = 1 << 7; unsigned char b = 1 << 7; printf("%hd %hu\n", ~a, ~b); let's see ~a is really ~(int)a. Likewise ~b is really ~(int)b. #define printf __builtin_printf int main(void) { signed char a = 1 << 7; unsigned char b = 1 << 7; printf("%x %x\n", ~a, ~b); } --- CUT ---- 7f ffffff7f This is the correct behavior. As (int)(unsigned char)a does a zero extend as the unsigned char fits directly in an int. Think of this way. The value from unsigned char and signed char are unchanged when promoted into int. So with the first one you get -128 and the second case you get 128. and then you take the ~ and you get 127 and (~(1<<7)) .