《C 程序設(shè)計位運算》由會員分享,可在線閱讀,更多相關(guān)《C 程序設(shè)計位運算(46頁珍藏版)》請在裝配圖網(wǎng)上搜索。
1、單擊此處編輯母版標(biāo)題樣式,單擊此處編輯母版副標(biāo)題樣式,第12章 位運算,12.1位運算符和位運算,12.2位運算舉例,12.3位段,習(xí)題,C語言是為描述系統(tǒng)而設(shè)計的,因此它應(yīng)當(dāng)具有匯編語言所能完成的一些功能。C語言既具有高級語言的特點,又具有低級語言的功能,因而具有廣泛的用途和很強(qiáng)的生命力。第9章介紹的指針運算和本章將介紹的位運算就很適合于編寫系統(tǒng)軟件的需要,是C語言的重要特色。在計算機(jī)用于檢測和控制領(lǐng)域中要用到位運算的知識,因此讀者應(yīng)當(dāng)學(xué)習(xí)和掌握本章的內(nèi)容。,所謂位運算是指進(jìn)行二進(jìn)制位的運算。在系統(tǒng)軟件中,常要處理二進(jìn)位的問題。例如,將一個存儲單元中的各二進(jìn)位左移或右移一位,兩個數(shù)按位相加等
2、。C語言提供位運算的功能,與其他高級語言(如PASCAL)相比,它顯然具有很大的優(yōu)越性。,12.1.1“按位與運算符(&),參加運算的兩個數(shù)據(jù),按二進(jìn)位進(jìn)行“與運算。如果兩個相應(yīng)的二進(jìn)位都為1,那么該位的結(jié)果值為1,否那么為0。即,0&0=0;0&1=0;1&0=0;1&1=1;,例如:3&5并不等于8,應(yīng)該是按位與。,3=00000011,(&)5=00000101,00000001,12.1位運算符和位運算,因此,3&5的值得1。如果參加&是負(fù)數(shù)運算的是負(fù)數(shù)(如-3&-5),那么以補(bǔ)碼形式表示為二進(jìn)制數(shù),然后按位進(jìn)行“與運算。,按位與有一些特殊的用途:,(1)清零。如果想將一個單元清零,即
3、使其全部二進(jìn)位為0,只要找一個二進(jìn)制數(shù),其中各個位符合以下條件:原來的數(shù)中為1的位,新數(shù)中相應(yīng)位為0。然后使二者進(jìn)行&運算,即可到達(dá)清零目的。,如:原有數(shù)為00101011,另找一個數(shù),設(shè)它為10010100,它符合以上條件,即在原數(shù)為1的位置上,它的位值均為0。將兩個數(shù)進(jìn)行&運算:,00101011,(&)10010100,00000000,其道理是顯然的。當(dāng)然也可以不用10010100這個數(shù)而用其他數(shù)(如01000100)也可以,只要符合上述條件即可。,(2)取一個數(shù)中某些指定位。如有一個整數(shù)a(2個字節(jié)),想要其中的低字節(jié)。只需將a與(737)8按位與即可。見圖12.1。,圖12.2,圖
4、12.1,c=a&b,b為八進(jìn)制數(shù)的377,運算后c只保存a的低字節(jié),高字節(jié)為0。,如果想取兩個字節(jié)中的高字節(jié),只需c=a&0177400(0177400表示八進(jìn)制數(shù)的177400)。見圖12.2。,(3)要想將哪一位保存下來,就與一個數(shù)進(jìn)行&運算,此數(shù)在該位取1,如:有一數(shù)01010100,想把其中左面第3、4、5、7、8位保存下來,可以這樣運算:,01010100 (十進(jìn)制數(shù)84),(&)00111011 (十進(jìn)制數(shù)59),00010000(十進(jìn)制數(shù)16),即a=84,b=59,c=a&b=16。,12.1.2按位或運算符(|),兩個相應(yīng)的二進(jìn)位中只要有一個為1,該位的結(jié)果值為1。即0|0
5、=0;0|1=1;1|0=1;1|1=1。例如:060|017,將八進(jìn)制數(shù)60與八進(jìn)制數(shù)17進(jìn)行按位或運算。,00110000,(|)00001111,00111111,低4位全為1。如果想使一個數(shù)a的低4位改為1,只需將a與017進(jìn)行按位或運算即可。,按位或運算常用來對一個數(shù)據(jù)的某些位定值為1。如:a是一個整數(shù)(16位),有表達(dá)式a|0377那么低8,位全置為1。高8位保存原樣。,12.1.3“異或運算符(),異或運算符也稱XOR運算符。它的規(guī)那么是假設(shè)參加運算的兩個二進(jìn)位同號,那么結(jié)果為0(假);異號那么為1(真)。即00=0;01=1;10=1;11=0;如:,00111001 (十進(jìn)制
6、數(shù)57,八進(jìn)制數(shù)071),()00101010 (十進(jìn)制數(shù)42,八進(jìn)制數(shù)052),00010011 (十進(jìn)制數(shù)19,八進(jìn)制數(shù)023),即071052,結(jié)果為023(八進(jìn)制數(shù))。,“異或的意思是判斷兩個相應(yīng)的位值是否為“異,為“異(值不同)就取真(1),否那么為假(0)。,下面舉例說明運算符的應(yīng)用:,(1)使特定位翻轉(zhuǎn),假設(shè)有01111010,想使其低4位翻轉(zhuǎn),即1變?yōu)?,0變?yōu)?。可以將它與00001111進(jìn)行運算,即,01111010,()00001111,01110101,結(jié)果值的低4位正好是原數(shù)低4位的翻轉(zhuǎn)。要使哪幾位翻轉(zhuǎn)就將與其進(jìn)行運算的該幾位置為1即可。這是因為原數(shù)中值為1的位與1進(jìn)
7、行運算得0,原數(shù)中的位值0與1進(jìn)行運算的結(jié)果得1。,(2)與0相,保存原值如,01200=012,00001010,()00000000,00001010,因為原數(shù)中的1與0進(jìn)行運算得1,00得0,故保存原數(shù)。,(3)交換兩個值,不用臨時變量,假設(shè)a=3,b=4。想將a和b的值互換,可以用以下賦值語句實現(xiàn):,a=ab;,b=ba;,a=ab;,可以用下面的豎式來說明:,a=011,()b=100,a=111(ab的結(jié)果,a已變成7),()b=100,b=011(ba的結(jié)果,b已變成3),()a=111,a=100(ab的結(jié)果,a變成4),即等效于以下兩步:,b=b(ab)=bab=abb=a0
8、=a,它相當(dāng)于上面的前兩個賦值語句:“a=ab;和“b=ba;。bb的結(jié)果為0,因為同一個數(shù)與,本身相,結(jié)果必為0。現(xiàn)在b已得到a的值3。在上式中除了第一個b以外,其余的a、b都是指原來的a、b。,再執(zhí)行a=ab=(ab)(bab)=abbab=aabbb=b。,a得到b原來的值。,12.1.4“取反運算符(),是一個單目(元)運算符,用來對一個二進(jìn)制數(shù)按位取反,即將0變1,1變0。例如025是對八進(jìn)制數(shù)25(即二進(jìn)制數(shù)00010101)按位求反。,000000000010101,(),即八進(jìn)制數(shù)177752。因此,025的值為八進(jìn)制數(shù)177752。不要以為025的值是-025。,下面舉一例說
9、明運算符的應(yīng)用。,假設(shè)一個整數(shù)a為16位,想使最低一位為0,可以用,a=a&0177776,177776a的值為八進(jìn)制數(shù)75,a&0177776的運算可以表示如下:,0000000000111101,0000000000111100,a的最后一個二進(jìn)位變成0。但如果將C源程序移植到以32位存放一個整數(shù)的計算機(jī)系統(tǒng)(如AX 11/780)上,由于一個整數(shù)用4個字節(jié)(32位表示),想將最后一位變成0就不能用a&0177776了。讀者可以自己算一下,當(dāng)時,a&0177776的結(jié)果是什么?,為了適應(yīng)以32位存放一個整數(shù)的計算機(jī)系統(tǒng),應(yīng)改用,a&037777777776,這樣改動使移植性差了,可以改用,
10、a=a&1,它對以16位和以32位存放一個整數(shù)的情況都適用,不必作修改。因為在以2個字節(jié)存儲一個整數(shù)時,1的二進(jìn)制形式為0000000000000001,1是111111,運算符的優(yōu)先級別比算術(shù)運算符、關(guān)系運算符、邏輯運算符和其他位運算符都高,例如:a&b,先進(jìn)行a運算,然后進(jìn)行&運算。,12.1.5左移運算符(),用來將一個數(shù)的各二進(jìn)位全部左移假設(shè)干位。例如:,a=a2,將a的二進(jìn)制數(shù)左移2位,右補(bǔ)0。假設(shè)a=15,即二進(jìn)制數(shù)00001111,左移2位得00111100,即十進(jìn)制數(shù)60(為簡單起見,我們用8位二進(jìn)制數(shù)表示十進(jìn)制數(shù)15,如果用16位,結(jié)果是一樣的)。,高位左移后溢出,舍棄不起作
11、用。,左移1位相當(dāng)于該數(shù)乘以2,左移2位相當(dāng)于該數(shù)乘以22=4。上面舉的例子152=60,即乘了4。但此結(jié)論只適用于該數(shù)左移時被溢出舍棄的高位中,不包含1的情況。例如,假設(shè)以一個字節(jié)(8位)存一個整數(shù),假設(shè)a為無符號整型變量,那么a=64時,左移一位時溢出的是0,而左移2位時,溢出的高位中包含1。左移比乘法運算快得多,有些C編譯程序自動將乘2的運算用左移一位來實現(xiàn),將乘2n的冪運算處理為左移n位。,12.1.6 右移運算符(),a2表示將a的各二進(jìn)位右移2位。移到右端的低位被舍棄,對無符號數(shù),高位補(bǔ)0。如a=017時:,11a為 00001111,a2為 00000011|11,此二位舍棄,右
12、移一位相當(dāng)于除以2,右移n位相當(dāng)于除以2n。在右移時,需要注意符號位問題。對無符號數(shù),右移時左邊高位移入0。對于有符號的值,如果原來符號位為0(該數(shù)為正),那么左邊也是移入0,如同上例表示的那樣。如果符號位原來為1(即負(fù)數(shù)),那么左邊移入0還是1,要取決于所用的計算機(jī)系統(tǒng)。有的系統(tǒng)移入0,有的移入1。移入0的稱為“邏輯右移,即簡單右移。移入1的稱為“算術(shù)右移。例如,a的值為八進(jìn)制數(shù)113755。,邏輯右移時),算術(shù)右移時),在有些系統(tǒng)上,a1得八進(jìn)制數(shù)045766,而在另一些系統(tǒng)上可能得到的是145766。Turbo C和其他一些C編譯采用的是算術(shù)位移,即對有符號數(shù)右移時,如果符號位原來為1,
13、左面移入高位的是1。,12.1.7位運算賦值運算符,位運算符與賦值運算符可以組成復(fù)合賦值運算符如:&=,|=,=,=,=,例如,a&=b相當(dāng)于 a=a&b。a =2相當(dāng)于:a=a 4,設(shè)置一個低4位全為1,其余全為0的數(shù)。可用下面方法實現(xiàn):,(0 4),0的全部二進(jìn)制為全1,左移4位,這樣右端低4位為0。見下面所示:,0:0000000000,0:1111111111,04:1111110000,(0 4)&(0 4),根據(jù)上一節(jié)介紹的方法,與低4位為1的數(shù)進(jìn)行&運算,就能將這4位保存下來。,程序如下:,main(),unsigned a,b,c,d;,scanf(%o,&a);,b=a4;,
14、c=(04);,d=b&c;,printf(%o,%dn%o,%dn,a,a,d,d);,運行情況如下:,331,331,217(a的值),15,13 (d的值),輸入a的值為八進(jìn)制數(shù)331,即十進(jìn)制數(shù)217,其二進(jìn)制形式為11011001。經(jīng)運算最后得到的d為00001101,即八進(jìn)制數(shù)15,十進(jìn)制數(shù)13。,圖12.4,可以任意指定從右面第m位開始取其右面n位。只需將程序中的“b=a4改成“b=a(m-n+1)以及將“c=(04)改成“c=(0n)即可。,例12.2循環(huán)移位。要求將a進(jìn)行右循環(huán)移位。見圖12.4。圖12.4表示將a右循環(huán)移n位。即將a中原來左面(16-n)位右移n位,原來右端
15、n位移到最左面n位。今假設(shè)用兩個字節(jié)存放一個整數(shù)。為實現(xiàn)以上目的可以用以下步驟:,將a的右端n位先放到b中的高n位中??梢杂孟旅嬲Z句實現(xiàn):b=a(16-n);,將a右移n位,其左面高位n位補(bǔ)0??梢杂孟旅嬲Z句實現(xiàn):,c=an;,將c與b進(jìn)行按位或運算。即,c=c|b;,程序如下:,main(),unsigned a,b,c;,int n;,scanf(a=%o,n=%d,&a,&n);,b=a(16-n);,c=an;,c=c|b;,printf(%on%o,a,c);,運行情況如下:,a=157653,n=3,0 157653,75765,12.3位段,以前曾介紹過對內(nèi)存中信息的存取一般以字
16、節(jié)為單位。實際上,有時存儲一個信息不必用一個或多個字節(jié),例如,“真或“假用0或1表示,只需1位即可。在計算機(jī)用于過程控制、參數(shù)檢測或數(shù)據(jù)通信領(lǐng)域時,控制信息往往只占一個字節(jié)中的一個或幾個二進(jìn)位,常常在一個字節(jié)中放幾個信息。那么,怎樣向一個字節(jié)中的一個或幾個二進(jìn)位賦值和改變它的值呢?可以用以下兩種方法:,(1)可以人為地在一個字節(jié)data中設(shè)幾項。例如:a、b、c、d分別占2位、6位、4位、4位(見圖12.5)。如果想將c的值變?yōu)?2(設(shè)c原來為0),可以這樣:,圖12.5,將數(shù)12左移4位,使1100成為右面起第47位。,將data與“124 進(jìn)行“按位或 運算,即可使c的值變成12。,如果c的原值不為0,應(yīng)先使之為0??梢杂孟旅娣椒ǎ?data=data&0177417,0177417的二進(jìn)制表示為,11 11111 1 0000 1111,a b c d,也就是使第47位全為0,其他位全為1。它與data進(jìn)行 15是c的最大值,c共占4位,最大值為1111即15。154是將1111移到47位。再取反,就使47位變成0,其余位全是1。即,15:0000000000001111,15