位移位運算符是將數據當作二進制數,對其進行向左或向右移動若干位的運算。位移位運算符分爲左移和右移兩種,均爲雙目運算符。第一運算對象是移位對象,第二個運算對象是所移的二進制位數。
位移位運算符的運算對象、運算規則與結果、結合性如表2-16所看到的。
移位時,移出的位數全部丟棄,移出的空位補入的數與左移仍是右移花接木有關。假設是左移,則規定補入的數全部是0;假設是右移,還與被移位的數據是否帶符號有關。如果不帶符號數,則補入的數全部爲0;如果帶符號數,則補入的數全部等於原數的最左端位上的原數(即原符號位)。詳細移位規則例如如下所看到的。
位移位運算符的優先級例如如下:
·算術運算符 優先於 位移位運算符 優先於 關係運算符
·位移位運算符是同級別的,結合性是自左向右
好比,設無符號短整型變量a爲0111(相應二進制數爲0000000001001001),
則:a<<3 結果爲01110(相應二進制數爲0000001001001000),a不變
a>>4 結果爲04 (相應二進制數爲0000000000000100),a不變
又如,設短整型變量a爲-4(相應二進制數爲 1111111111111100),
則:a<<3 結果爲-32(相應二進制數爲1111111111100000),a不變
a>>4 結果爲-1(相應二進制數爲1111111111111111),a不變spa
先說左移,左移就是把一個數的所有位都向左移動若干位,在C中用<<運算符.好比:對象
int i = 1;
i = i << 2; //把i裏的值左移2位input
也就是說,1的2進制是000...0001(這裏1前面0的個數和int的位數有關,32位機器,gcc裏有31個0),左移2位以後變成 000... 0100,也就是10進制的4,因此說左移1位至關於乘以2,那麼左移n位就是乘以2的n次方了(有符號數不全然適用,因爲左移有可能致使符號變化,如下解釋緣由)編譯器
需要注意的一個問題是int類型最左端的符號位和移位移出去的狀況.咱們知道,int是有符號的整形數,最左端的1位是符號位,即0正1負,那麼移位的時候就會出現溢出,好比:it
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.class
左移裏一個比較特殊的狀況是當左移的位數超過該數值類型的最大位數時,編譯器會用左移的位數去模類型的最大位數,而後按餘數進行移位,如:效率
int i = 1, j = 0x80000000; //設int爲32位
i = i << 33; // 33 % 32 = 1 左移1位,i變成2
j = j << 33; // 33 % 32 = 1 左移1位,j變成0,最高位被丟棄變量
在用gcc編譯這段程序的時候編譯器會給出一個warning,說左移位數>=類型長度.那麼實際上i,j移動的就是1位,也就是33%32 後的餘數.在gcc下是這個規則,別的編譯器是否是都同樣現在還不清楚.gcc
總之左移 就是: 丟棄最高位,0補最低位
再說右移,明確了左移的道理,那麼右移就比較好理解了.
右移的概念和左移相反,就是往右邊挪動若干位,運算符是>>.
右移對符號位的處理和左移不一樣,對於有符號整數來講,比方int類型,右移會保持符號位不變,好比:
int i = 0x80000000;
i = i >> 1; //i的值不會變成0x40000000,而會變成0xc0000000
就是說,符號位向右移動後,正數的話補0,負數補1,也就是彙編語言中的算術右移.相同當移動的位數超過類型的長度時,會取餘數,而後移動餘數個位.
負數10100110 >>5(若是字長爲8位),則獲得的是 11111101
總之,在C中,左移是邏輯/算術左移(二者全然一樣),右移是算術右移,會保持符號位不變 .實際應用中可以依據狀況用左/右移作高速的乘 /除運算,這樣會比循環效率高很是多.
在很是多系統程序中常要求在位(bit)一級進行運算或處理。C語言提供了位運算的功能, 這使得C語言也能像彙編語言同樣用來編寫系統程序。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
操做符 做用
────────────────────────────
& 位邏輯與
| 位邏輯或
^ 位邏輯異或
- 位邏輯反
>> 右移
<< 左移
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
按位運算是對字節或字中的實際位進行檢測、設置或移位, 它僅僅適用於字符型和整數型變量以及它們的變體, 對其餘數據類型不適用。
咱們要注意區分位運算和邏輯運算。
1. 按位與運算 按位與運算符"&"是雙目運算符。其功能是參與運算的兩數各相應的二進位相與。僅僅有相應的兩個二進位均爲1時,結果位才爲1 ,不然爲0。參與運算的數以補碼方式出現。
好比:9&5可寫算式例如如下: 00001001 (9的二進制補碼)&00000101 (5的二進制補碼) 00000001 (1的二進制補碼)可見9&5=1。
按位與運算通常常使用來對某些位清0或保留某些位。好比把a 的高八位清 0 , 保留低八位, 可做 a&255 運算 ( 255 的二進制數爲0000000011111111)。
main(){
int a=9,b=5,c;
c=a&b;
printf("a=%d/nb=%d/nc=%d/n",a,b,c);
}
2. 按位或運算 按位或運算符「|」是雙目運算符。其功能是參與運算的兩數各相應的二進位相或。僅僅要相應的二個二進位有一個爲1時,結果位就爲1。參與運算的兩個數均以補碼出現。
好比:9|5可寫算式例如如下: 00001001|00000101
00001101 (十進制爲13)可見9|5=13
main(){
int a=9,b=5,c;
c=a|b;
printf("a=%d/nb=%d/nc=%d/n",a,b,c);
}
3. 按位異或運算 按位異或運算符「^」是雙目運算符。其功能是參與運算的兩數各相應的二進位相異或,當兩相應的二進位相異時,結果爲1。參與運算數仍以補碼出現,好比 9^5可寫成算式例如如下: 00001001^00000101 00001100 (十進制爲12)
main(){
int a=9;
a=a^15;
printf("a=%d/n",a);
}
4. 求反運算 求反運算符~爲單目運算符,具備右結合性。 其功能是對參與運算的數的各二進位按位求反。好比~9的運算爲: ~(0000000000001001)結果爲:1111111111110110
5. 左移運算 左移運算符「<<」是雙目運算符。其功能把「<< 」左邊的運算數的各二進位全部左移若干位,由「<<」右邊的數指定移動的位數,高位丟棄,低位補0。好比: a<<4 指把a的各二進位向左移動4位。如a=00000011(十進制3),左移4位後爲00110000(十進制48)。
6. 右移運算 右移運算符「>>」是雙目運算符。其功能是把「>> 」左邊的運算數的各二進位全部右移若干位,「>>」右邊的數指定移動的位數。好比:設 a=15,a>>2 表示把000001111右移爲00000011(十進制3)。應該說明的是,對於有符號數,在右移時,符號位將隨同移動。當爲正數時, 最高位補0,而爲負數時,符號位爲1,最高位是補0或是補1 取決於編譯系統的規定。
main(){
unsigned a,b;
printf("input a number: ");
scanf("%d",&a);
b=a>>5;
b=b&15;
printf("a=%d/tb=%d/n",a,b);
}
請再看一例!
main(){
char a='a',b='b';
int p,c,d;
p=a;
p=(p<<8)|b;
d=p&0xff;
c=(p&0xff00)>>8;
printf("a=%d/nb=%d/nc=%d/nd=%d/n",a,b,c,d);
}
當進行按位與或時,最好使用16進制,在程序中這樣表示:0x01 表示0000 0001 因此,字符類型a的最高位強制1可以這樣:a=a|0x80。其它的可以依次類推!