1. 程式人生 > >左移右移置位

左移右移置位

int 裏的 通過 超過 二進制 方法 原碼 可能 字長

int i = 1;
i = i << 2; //把i裏的值左移2位

也就是說,1的2進制是000...0001(這裏1前面0的個數和int的位數有關,32位機器,gcc裏有31個0),左移2位之後變成 000...0100,也就是10進制的4,所以說左移1位相當於乘以2,那麽左移n位就是乘以2的n次方了(有符號數不完全適用,因為左移有可能導致符號變化,下面解釋原因)

int i = 0x40000000; //16進制的40000000,為2進制的01000000...0000
i = i << 1;

那麽,i在左移1位之後就會變成0x80000000,也就是2進制的100000...0000,符號位被置1,其他位全是0,變成了int類型所能表示的最小值,32位的int這個值是-2147483648,溢出.如果再接著把i左移1位會出現什麽情況呢?在C語言中采用了丟棄最高位的處理方法,丟棄了1之後,i的值變成了0.

總之左移就是: 丟棄最高位,0補最低位

右移對符號位的處理和左移不同,對於有符號整數來說,比如int類型,右移會保持符號位不變,例如:

int i = 0x80000000;
i = i >> 1; //i的值不會變成0x40000000,而會變成0xc0000000

就是說,符號位向右移動後,正數的話補0,負數補1,也就是匯編語言中的算術右移.同樣當移動的位數超過類型的長度時,會取余數,然後移動余數個位.

負數10100110 >>5(假設字長為8位),則得到的是 11111101

總之,在C中,左移是邏輯/算術左移(兩者完全相同),右移是算術右移,會保持符號位不變.實際應用中可以根據情況用左/右移做快速的乘/除運算,這樣會比循環效率高很多.

左移操作(<<)
規則:
右邊空出的位用0填補
高位左移溢出則舍棄該高位。
計算機中常用補碼表示數據:
數據 127,補碼和原碼一樣:0111 1111。
左移一位: 1111 1110 -> 這個補碼對應的原碼為:1000 0010 對應十進制:-2
左移二位: 1111 1100 -> 這個補碼對應的原碼為:1000 0100 對應十進制:-4
左移三位: 1111 1000 -> 這個補碼對應的原碼為:1000 1000 對應十進制:-8
左移四位: 1111 0000 -> 這個補碼對應的原碼為:1001 0000 對應十進制:-16
左移五位: 1110 0000 -> 這個補碼對應的原碼為:1010 0000 對應十進制:-32
左移六位: 1100 0000 -> 這個補碼對應的原碼為:1100 0000 對應十進制:-64
左移七位: 1000 0000 -> 這個補碼對應的原碼為:1000 0000 對應十進制:-128
左移八位: 0000 0000 -> 這個補碼對應的原碼為:0000 0000 對應十進制:0
註:
原碼到補碼的計算方式:取反+1,正數的補碼和反碼等於源碼(化為二進制後高位補0符號位)


補碼到原碼的計算方式:-1再取反。(求反碼:符號位不變,數值取反;求補碼:符號位不變,反碼最低位加1,1+1=0進1)
數據-1,它的原碼為1000 0001,補碼為1111 1111
左移一位: 1111 1110 -> 這個補碼對應的原碼為:1000 0010 對應十進制:-2
左移二位: 1111 1100 -> 這個補碼對應的原碼為:1000 0100 對應十進制:-4
左移三位: 1111 1000 -> 這個補碼對應的原碼為:1000 1000 對應十進制:-8
左移四位: 1111 0000 -> 這個補碼對應的原碼為:1001 0000 對應十進制:-16
左移五位: 1110 0000 -> 這個補碼對應的原碼為:1010 0000 對應十進制:-32
左移六位: 1100 0000 -> 這個補碼對應的原碼為:1100 0000 對應十進制:-64
左移七位: 1000 0000 -> 這個補碼對應的原碼為:1000 0000 對應十進制:-128
左移八位: 0000 0000 -> 這個補碼對應的原碼為:0000 0000 對應十進制:0
可以看出127和-1的結果完全一樣。移位操作與正負數無關,它只是忠實的將所有位進行移動,補0,舍棄操作。
右移操作(>>)
規則:
左邊空出的位用0或者1填補。正數用0填補,負數用1填補。註:不同的環境填補方式可能不同;

低位右移溢出則舍棄該位。

1、127的補碼:0111 1111

右移一位: 0011 1111 -> 原碼同補碼一樣 對應十進制:63

右移二位: 0001 1111 -> 原碼同補碼一樣 對應十進制:31

右移三位: 0000 1111 -> 原碼同補碼一樣 對應十進制:15

右移四位: 0000 0111 -> 原碼同補碼一樣 對應十進制:7

右移五位: 0000 0011 -> 原碼同補碼一樣 對應十進制:3

右移六位: 0000 0001 -> 原碼同補碼一樣 對應十進制:1

右移七位: 0000 0000 -> 原碼同補碼一樣 對應十進制:0

右移八位: 0000 0000 -> 原碼同補碼一樣 對應十進制:0

2、-128的補碼:1000 0000

右移一位: 1100 0000 -> 這個補碼對應的原碼為:1100 0000 對應十進制:-64

右移二位: 1110 0000 -> 這個補碼對應的原碼為:1010 0000 對應十進制:-32

右移三位: 1111 0000 -> 這個補碼對應的原碼為:1001 0000 對應十進制:-16

右移四位: 1111 1000 -> 這個補碼對應的原碼為:1000 1000 對應十進制:-8

右移五位: 1111 1100 -> 這個補碼對應的原碼為:1000 0100 對應十進制:-4

右移六位: 1111 1110 -> 這個補碼對應的原碼為:1000 0010 對應十進制:-2

右移七位: 1111 1111 -> 這個補碼對應的原碼為:1000 0001 對應十進制:-1

右移八位: 1111 1111 -> 這個補碼對應的原碼為:1000 0001 對應十進制:-1

常見應用
左移相當於*2,只是要註意邊界問題。如char a = 65; a<<1 按照*2來算為130;但有符號char的取值範圍-128~127,已經越界,多超出了3個數值,所以從-128算起的第三個數值-126才是a<<1的正確結果。
而右移相當於除以2,只是要註意移位比較多的時候結果會趨近去一個非常小的數,如上面結果中的-1,0。
其它的四種位運算:
與運算(&)
1、與0相與可清零
2、與1相與可保留原值
或運算(|)
1、與0相或可保留原值
2、與1相與可齊設1
異或運算(^)
1、與0異或保留原值
2、與1異或比特值反轉
3、可通過某種算法,使用異或實現交換兩個值
異或運算是有結合律的
取反(~)

來源:https://www.cnblogs.com/yyangblog/archive/2011/01/14/1935656.html

左移右移置位