Strange behavior of bitwise NOT (~)
How do I explain the following behavior?
#include<iostream>
using namespace std;
int main(){
unsigned char a = 8;
cerr <&l开发者_如何学Pythont; "a: " << (int)a << '\n';
unsigned char b = (~a) >> 6;
cerr << "b: " << (int)b << '\n';
unsigned char c = (~a);
c = c >> 6;
cerr << "c: " << (int)c << '\n';
return 0;
}
Output:
a: 8
b: 255
c: 3
After further testing it seems that (~a)
becomes an int
rather than unsigned char
. This is why the 1
's get shifted in.
What's going on?
EDIT: My compiler is just standard gcc 4.1.2
All arithmetic and bitwise operators in C always widen their arguments to at least int
if they were originally shorter integral types. That's just how the language is defined. The language specification calls this the "integral promotion".
(The underlying reason for this is to make it easier to implement C on architectures where the hardware does not support efficient operations on shorter quantities than a full machine word. Of course, it's also partly just because it has always worked that way and cannot be changed without breaking a lot of existing code that depends on this behavior).
~a = 0xFFFFFFF7
, so b = (~a) >> 6
results in b = 0xFF
; In case of c we have c = (~a);
resulting in c = 0xF7
, therefore c>>6
will be 3. Henning Makholm explains integer promotion nicely above. This article is also useful.
a = 8
~a = -9 (int)
~a >> 6 = -1 (int)
(unsigned char)-1 = 255
because this line...
unsigned char b = (~a) >> 6;
compiler build the temporary var is signed char (~a) and after the shift right and LSB byte b is 0xff
but this lines...
unsigned char c = (~a);
c = c >> 6;
compiler not needed to build the temporary var and (~a) value is 0x7f, and after the shift right c is 0x03
精彩评论