我們都知道,數據在計算機裡是以二進制形 式表示的。在實際問題中,常常 也有一些數據對象的情況比較簡單,只需要一個或幾個二進制位就能夠編碼表示。如果在一個軟件系統中這種數據對象非常多,用一個基本數據類型表示,對計算機 資源是一種浪費。另一方面,許多系統程序需要對二進制位表示的數據直接操作,例如許多計算機硬件設備的狀態信息通常是用二進制位串形式表示的,如果要對硬 件設備進行操作,也要送出一個二進制位串的方式發出命令。由於C語言的主要設計目的是面向復雜的系統程序設計,所以它特別提供了對二進制位的操作功能,稱 為位運算。
位運算應用於整型數據,即把整型數據看成是固定的二進制序列,然後對這些二進制序列進行按 位運算。與其它 高級語言相比,位運算是C語言的特點之一。但是由於位運算的應用涉及更深入和更廣泛的內容,初學者不必細究,在實際應用中可逐步體會其優越性。這部分內容 相對比較獨立,讀者可根據實際需要選擇學習。本書僅對位運算及其應用作簡要的介紹。
3.5.1 位運算符
因為一個二進制位只能取值為0或者1,所以位運算就是從具有0或者1值的運算對象出發,計 算出具有0或者1 值的結果。C語言提供了6種基本位運算功能:位否定、位與、位或、位異或、位左移和位右移。其中除位否定是單目運算外,其余5種均為雙目運算,6個位運算 符分為4個優先級別,參見表3-9。
表3-9 邏輯運算符
運算符 含義 運算對象個數 結合方向 優先級
~ 按位求反 單目運算符 自右向左 1
<< 按位左移 雙目運算符 自左向右 2
>> 按位右移 雙目運算符 自左向右 2
& 按位與 雙目運算符 自左向右 3
| 按位或 雙目運算符 自左向右 4
^ 按位異或 雙目運算符 自左向右 5
說明:
① 位運算的優先級是:~→<<、>>→&→|→^。
② 位運算的運算對象只能是整型(int)或字符型(char)的數據。
③ 位運算是對運算量的每一個二進制位分別進行操作。
3.5.2 按位邏輯運算
按位邏輯運算包括:位與、位或、位異或和位否定等四種運算。為了幫助讀者理解,我們設a和b都是16位二進制整數,它們的值分別是:
a: 1010,1001,0101,0111
b: 0110,0000,1111,1011
為了便於閱讀,a和b中每4位用一個逗號分開。以下介紹對於a和b的位與、位或、位異或和位否定等按位邏輯運算。
1.按位與運算 (&)
按位與是對兩個運算量相應的位進行邏輯與,"&"的運算規則與邏輯與"&&"相同。
按位與表達式:c=a&b
a: 1010,1001,0101,0111
& b: 0110,0000,1111,1011
c: 0010,0000,0101,0011
2.按位或運算(|)
按位或是對兩個運算量相應的位進行邏輯或操作,其運算規則與邏輯或"||"相同。
按位或表達式:c=a|b
a: 1010,1001,0101,0111
| b: 0110,0000,1111,1011
c: 1110,1001,1111,1111
3.按位異或運算(^)
按位異或運算的規則是:兩個運算量的相應位相同,則結果為0,相異則結果為1。
即: 0^0=0 0^1=1 1^0=1 1^1=0
按位異或表達式:c=a^b
a: 1010,1001,0101,0111
^ b: 0110,0000,1111,1011
c: 1100,1001,1010,1100
可見,異或運算的含義是:兩個相應位的值相異,則結果為1,相同則為0。
4.按位求反運算符(~)
按位求反運算運算規則是將二進制表示的運算對象按位取反,即將1變為0,將0變為1。
按位異或表達式:c=~a
~ a: 1010,1001,0101,0111
c: 0101,0110,1010,1000
5.按位邏輯運算的應用
例3-8:設 int x=7,求y=~x
y=~x=~7=~(0000,0000,0000,0111)=1111,1111,1111,1000=-8
可見,對x的值(7)按位求反結果恰為-8的補碼表示,其原因是計算機中有:
整數求負=整數求補=按位求反+1
所以:按位求反=整數求負-1。
請注意求反運算與單目減和邏輯非運算的區別:
y=-x; 結果為:y=-7,
y=!x; 結果為:y=0。
例3-9:用按位與運算屏蔽特定位(將指定位清為0)。
設 n=051652(八進制數),計算m=n&0177,則:m=052。
n: 0,101,001,110,101,010
& 0177: 0,000,000,001,111,111
m: 0,000,000,000,101,010
經過位與運算,將n前9位屏蔽掉,即截取n的後7位。
例3-10:用按位與運算保留特定位。
要想將一個變量n的特定位保留下來,只要設一個數,使該數的某些位為1,這些位是與要保留的n的特定位相對應的位,再將n與該數按位與。
設 n=011050(為八進制數。對應的二進制為:0,001,001,000,101,000),要將n的右起第2、4、6、8、10位保留下來,只要 n=n&01252,則有:
n: 0,001,001,000,101,000
& 01252: 0,000,001,010,101,010
n: 0,000,001,000,101,000 (n=01050)
注意,按位與的"&"功能與取地址運算的"&"不同,盡管兩者采用了相同的符號。
例3-11:用按位或運算將指定的位置為1。
設:x=061,y=016,則z=a|b為:
x: 0000,0000,0011,0001
| y: 0000,0000,0000,1110
z: 0000,0000,0011,1111
即將x或y中為1的位的相應位置成1,其結果是z中的後6位為1。
例3-12:用按位異或運算將某個量的特定位翻轉。
要將變量n的特定位翻轉,即原來為1的變0,為0的變1,只要設一個數,使該數的某些位為1,這些位是與n中要翻轉的相對應的位,然後將n與該數進行按位異或運算。
設:a=015,要將後四位翻轉,只要a=a^017,則:
a: 0000,0000,0011,1101
^ 017: 0000,0000,0011,1111
a: 0000,0000,0000,0010
3.5.3 移位運算
C語言提供了兩個移位運算:左移和右移,它們是把整數作為二進制位序列,求出把這個序列左 移若干位或者右移 若干位所得到的序列。左移和右移都是雙目運算,運算符左邊的運算對象是被左移或右移的數據,而運算符右邊的運算對象是指明移動的位數。數據左移或右移後空 出來的位置補0。
左移、右移運算表達式的一般形式為:
x << n 或 x >> n
其中x為移位運算對象,是要被移位的量;n是要移動的位數。
左移運算的規則是將x的二進制位全部向左移動n位,將左邊移出的高位捨棄,右邊空出的位補0。 右移是將x的各二進制位全部向右移動n位,將右邊移出的低 位捨棄,左邊高位空出要根據原來量符號位的情況進行補充,對無符號數則補0;對有符號數,若為正數則補0,若為負數則補1。
例如,設a=7,則:
b=a<<2 即:b=0000,0111<<2=0001,1100=28
c=a>>2 即:c=0000,0111>>2=0000,0001=1
左移的一個特殊用途是將整數值乘以2的冪,例如:左移運算表達式1<<4的計算結果是16,右移可以用於將整數值除乘2的冪。
3.5.4 位運算賦值運算符
位運算符與賦值運算符可以組成以下5種位運算賦值運算符:
&=、 |=、 >>=、 <<=、 ^=
由這些位運算賦值運算符可以構成位運算賦值表達式。例如:
x&=y 相當於:x=x&y
x<<=2 相當於:x=x<<2
x>>=3 相當於:x=x>>3
x^=5 相當於:x=x^5