左移和右移都是位運算的概念。我們知道計算機是基於二進制保存數據的,因此左移和右移的概念十分重要。本文約定是32位的機器。
[左移] 丟棄最高位,0補最低位
左移是把一個數按照二進制每位向左移動若干位,在c語言中用運算符 << 表示。例如:
int x = 1; x = x << 2; //把x的值左移2位
1對應的二進制數為000……0001(前面一共31個0),左移2位之后變成000……0100,在十進制下為4。所以看起來左移n位相當於乘以2的n次方。(有符號數不完全適用,因為左移有可能導致符號的變化,下面將給出解釋)
需要注意的是,當左移結果超出數據類型所能表示的范圍時,會出現溢出(產生數據丟失並造成結果錯誤)。我們知道,int是有符號的整型數,最高位是符號位,0表示正數,1表示負數。那么移位的時候就會出現溢出,例如:
int x = 0x40000000; //16進制的40000000,為2進制的0100……0000 x = x << 1;
這時候,x左移1位之后變成0x80000000,也就是2進制的1000……0000,符號位被置為1,變成了int型變量所能表示的最小值(因為負數是用補碼表示的,計算補碼:取反后加1),這個值在十進制下為-2147483648,我們成為溢出。如果把這個x再繼續左移1位,那么最高位被丟棄,最低位補0,x的值就變成了0。這看起來是一件有意思的事情,由此可見,左移簡單的理解為乘2的冪是不准確的。
左移中有一個比較特殊的情況,當左移的位數超過該數值類型的最大位數的時候,編譯器會先用左移的位數對最大位數取模,然后按照余數進行移位計算。例如:
int x = 1, y = 0x80000000; //y的值在二進制下是1000……0000 x = x << 33; //33 % 32 = 1 左移1位,x變成2 y = y << 33; //33 % 32 = 1 左移1位,最高位被丟棄,y變成0
int x = 0x80000000; //對應二進制的1000……0000 x = x >> 1; //x的值不會變成0x40000000(二進制的0100……0000),而是變成0xc0000000(二進制的1100……0000)
也就是說,符號位向右移動后,如果之前是正數,就在最高位補0;如果是負數,就在最高位補1(這樣的方式還是與負數用補碼存儲有關)。這也是匯編語言中的算術右移。
同樣的,當移動的位數超過類型的長度的時候,會先取余數,然后移動余數位。
這里值得指出的是,在c語言中,左移是邏輯/算數左移(兩者完全相同),右移是算術右移,會保持符號位不變。
