移位操作和二進制知識


常用的移位操作是<< 和 >> ,分別為左移和右移。我們在C語言中有算數移位和邏輯移位兩種。

算數移位:區分符號的移位       {C語言中直接是定義char m = 3}

邏輯移位:不區分符號的移位   {C語言中用unsigned char m = 3}

 

算數移位和邏輯移位有什么不同,舉例說明,例如:

(1)對無符號數3來說:

x<<1往左移一位,最左邊的位移掉了,最右邊的移進來的位補零。變成00000110,所以結果是6;[1*2^2 + 1*2^1 + 0*2^0 = 6]

x>>1往右邊移一位,由於是無符號數,所以邏輯右移,最右邊一位移掉,最左邊移進來的位補零,變成00000001,所以結果是1。[1*2^0 = 1]


(2)對於有符號數3來說:

x<<1往左移一位,最左邊的位移掉了,最右邊的移進來的位補零。變成00000110,所以結果是6;

x>>1往右邊移一位,由於是有符號數,可能發生邏輯右移,也可能發生算術右移,這一點,C標准並沒有明確地指定是使用邏輯右移還是算術右移。但大多數的機器都使用算術右移,變成00000001,所以結果還是1。

但是請注意,這只是說大多數的機器是這樣的,你敢保證自己不會碰到特殊情況嗎?


(3)對於有符號數-3來說:

x<<1往左移一位,最左邊的位移掉了,最右邊的移進來的位補零。變成11111010,結果是-6;[-(1*2^2 + 0*2^1 + 1*2^0 +1) = -6]

x>>1往右移一位,由於是有符號數,可能發生邏輯右移,也可能發生算術右移。大多數機器使用算術右移,變成11111110,結果是-2。[-(1*2^0 +1) = -2]


總結:

左移時總是移位和補零;

右移時無符號數是移位和補零,此時稱為邏輯右移;

而有符號數大多數情況下是移位和補最左邊的位(也就是補最高有效位),移幾位就補幾位,此時稱為算術右移。

 


補充:

1.匯編語言中的邏輯右移(SHR)是將各位依次右移指定位數,然后在左側補0,算術右移(SAR)是將各位依次右移指定位數,然后在左側用原符號位補齊
2.高級語言右移運算符(>>)是將一個數的二進位全部右移若干位,低位移出部分舍棄,左補0
3.高級語言右移和匯編語言中的邏輯右移功能一樣,但不同於算術右移

 

理解有誤的認知:對於有符號整型數的簡單認識就是:最高位為符號位,0為正,1為負。那么剩下幾位應該如何表示呢?理所當然的認為:既然是1表示為0000 0001(假設為8位整型數,下同),那么-1就應該表示為1000 0001了。

實際上在C語言里,-1的正確表示應該是1111 1111,即0xFF。因為C語言里,對整型數是采用Two’s complement表示法,而前面我的理解則是Sign-Magnitude表示法(浮點數采用該法)。在Two’s complement表示法里,1000 0001表示的是-127。

幾個特殊值,比如:

正值的最大表示為0111 1111,即127。[1*2^6 + 1*2^5 + 1*2^4 + 1*2^3 + 1*2^2 + 1*2^1 +1*2^0 = 127]

負值的最小表示為1000 0000,即-128。[-(1*2^6 + 1*2^5 + 1*2^4 + 1*2^3 + 1*2^2 + 1*2^1 +1*2^0 + 1) = -128]

並因此帶來幾個有趣的現象,比如從8位有符號數轉成16位有符號數的填充問題。以前想當然的是填0,但這是錯的,應該是填充符號位的值。比如-1=0xFF填充符號位1就應該變成0xFFFF。而如果填充的是0,那么變成0x80FF就不對了。

Two’s complement是不對稱的。一個數的正負值表示,除了最高位之外,其余位數也是不盡相同的。在C語言里,當在無符號數和有符號數之間進行轉換的時候,數值的二進制序列是不會改變的,改變的只是對該序列的解讀模式。比如有符號數-1轉換成無符號數就變成了255,雖然其二進制表示都是0xFF。如果不理解這一點,就會出Bug。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM