事情的發生:
某日工作中有個需求是將不同的數值存到char的前4位和后4位中。
恰好同事中有同樣取得32位int的前8位當成一個數值的代碼:
//取得32位中的高八位組成的值 #define U32_HIGH_8(val) ((val >> 24) & 0X000000FF)
好奇心就來了,在右移24位以后是否還有必要再與上(&)0x000000FF將高位的數據徹底清零呢?
討論:
考慮以下幾個問題:
(1)
char i = 0x40; //二進制中i的表示為:0100 0000 unsighed char j = 0x40; i <<= 1; j <<= 1; //問:i和j分別等於多少?
i 左移以后的二進制表示為:1000 0000,由定義的有符號char解釋為:i = -128
j 左移以后的二進制表示為:1000 0000,由定義的無符號(unsigned char)解釋為:i = 128
(2)
char i = 0x80;//二進制中表示為:1000 0000 char j = 0x40;//二進制中i的表示為:0100 0000 j >>= 1; i >>= 1; //問i和j等於多少?
i 右移以后的二進制表示為:1100 0000(右移對於負數來說符號位右移,高位補1),故i=-64
j 右移以后的二進制表示為:0010 0000(右移對於正數來說符號位右移,高位補0),故i=32
(3)
char i = -3;//二進制表示為:1111 1101 //i << 1是多少? i >> 1是多少?
i << 1的二進制表示為:1111 1010(左移為邏輯左移高位丟棄,低位補0),由有符號數char解釋為:-6
i >> 1的二進制表示為:1111 1110(右移為算術右移,對於負數來說高位補1),有有符號數char解釋為:2
左移右移總結:
右移左移涉及丟棄、補0或補1,但是最終對這一串二進制解釋成什么數值是通過變量的定義(是否unsigned)來決定的。
左移始終是邏輯左移,即丟棄高位,低位補0;
右移是算術右移,對於有符號數:正數右移高位補0,負數右移高位補1。對於無符號數:邏輯右移(即高位補0,低位丟棄);
結論:
那么開頭的問題是:是否還有必要再與上(&)0x000000FF將高位的數據徹底清零呢?
我認為還是有必要的,因為並不知道值的類型是否是無符號數(unsigned),假如原本的32位數是普通的int類型且二進制為(1000 0000……0000 0000),那么取高8位的時候的二進制表示(1111 1111……1000 0000),那么這個數解釋出來就會非常大且出錯。如果是無符號數的話還算正常。
因此為了避免日后定義錯類型導致的錯誤,還是將移位以后的二進制的高位與上(&)0,將高位徹底清0為好。