邏輯運算、位元運算

文章推薦指數: 80 %
投票人數:10人

接下來看看位元運算子(Bitwise operator),數位設計上有AND、OR、NOT、XOR 與補數等運算,在C 中提供這些運算的就是位元運算子,它們的對應分別是AND ( & )、OR( ... 回C語言目錄 在邏輯上有所謂的「且」、「或」與「反」運算,在C中也提供這幾個基本邏輯運算所需的邏輯運算子(Logicaloperator),分別為「且」(&&)、「或」(||)及「反相」(!)三個運算子。

來看看下面這個程式會輸出什麼? #include intmain(void){ intnum=75; printf("%d\n",num>70&&num<80); printf("%d\n",num>80||num<75); printf("%d\n",!(num>80||num<75)); return0; } 三段程式分別會輸出1、0與1,也就是分別表示真、假與真三種狀況。

&&運算中,如果左邊的式子已被評斷為假,則可立即判斷整個式子為假,因而右邊的式子就不會再評斷;||運算中如果左邊的式子已經被評斷為真,則可以判斷整個式子為真,因而右邊的式子就不會再評斷。

接下來看看位元運算子(Bitwiseoperator),數位設計上有AND、OR、NOT、XOR與補數等運算,在C中提供這些運算的就是位元運算子,它們的對應分別是AND(&)、OR(|)、NOT(!)、XOR(^)與補數(~)。

如果不會基本的位元運算,這邊可以提供一個程式來顯示各個運算的結果: #include intmain(void){ puts("AND運算:"); printf("0AND0\t\t%d\n",0&0); printf("0AND1\t\t%d\n",0&1); printf("1AND0\t\t%d\n",1&0); printf("1AND1\t\t%d\n\n",1&1); puts("OR運算:"); printf("0OR0\t\t%d\n",0|0); printf("0OR1\t\t%d\n",0|1); printf("1OR0\t\t%d\n",1|0); printf("1OR1\t\t%d\n\n",1|1); puts("XOR運算:"); printf("0XOR0\t\t%d\n",0^0); printf("0XOR1\t\t%d\n",0^1); printf("1XOR0\t\t%d\n",1^0); printf("1XOR1\t\t%d\n\n",1^1); puts("NOT運算:"); printf("NOT0\t\t%d\n",!0); printf("NOT1\t\t%d\n\n",!1); return0; } 執行結果如下: AND運算: 0AND00 0AND10 1AND00 1AND11 OR運算: 0OR00 0OR11 1OR01 1OR11 XOR運算: 0XOR00 0XOR11 1XOR01 1XOR10 NOT運算: NOT01 NOT10 C中的位元運算是逐位元運算,例如10010001與01000001作AND運算,是一個一個位元對應運算,答案就是00000001;而補數運算是將所有的位元0變1,1變0,例如00000001經補數運算就會變為11111110,例如下面這個程式所示: charnum=255; printf("%d\n",~num); 這段程式會在主控台顯示0,char使用一個位元組,若用於儲存正整數最大可儲存255的值,255的二進位表示法為11111111,經補數運算就是00000000,也就是0。

要注意的是,邏輯運算子與位元運算子也是很常被混淆的,像是&&為邏輯運算,而&為位元運算,||為邏輯運算,而|為位元運算,初學時可得多注意。

位元運算對初學者來說的確較不常用,但如果用的洽當的話,可以增進不少程式效率,例如下面這個程式可以判斷使用者的輸入是否為奇數: #include intmain(void){ intinput=0; printf("輸入正整數:"); scanf("%d",&input); printf("輸入為奇數?%c\n",input&1?'Y':'N'); return0; } 執行結果如下: 輸入正整數:5 輸入為奇數?Y 這個程式得以運算的原理是,奇數的數值若以二進位來表示,其最右邊的位元必為1,而偶數最右邊的位元必為0,所以使用1來與輸入的值作AND運算,由於1除了最右邊的位元為1之外,其他位元都會是0,與輸入數值AND運算的結果,只會留下最右邊位元為0或為1的結果,其他部份都被0AND運算遮掉了,這就是所謂「位元遮罩」,例如: 000001004 000000011 00000000判斷為偶數 000000113 000000011 00000001判斷為奇數 XOR的運算較不常見,這邊舉個簡單的XOR字元加密例子,先看看程式: #include intmain(void){ charch='A'; printf("beforeencoding:%c\n",ch); ch=ch^0x7; printf("afterencoding:%c\n",ch); ch=ch^0x7; printf("decoding:%c\n",ch); return0; } 執行結果如下: beforeencoding:A afterencoding:F decoding:A 0x7是C中整數的16進位寫法,其實就是10進位的7,將位元與1作XOR的作用其實就是位元反轉,0x7的最右邊三個位元為1,所以其實就是反轉ch的最後兩個字元,如下所示: 0100000165(對應ASCII的'A') 000001110x7 0100011070(對應ASCII中的'F') 同樣地,這個簡單的XOR字元加密,要解密也只要再進行相同的位元反轉就可以了。

要注意的是,雖然在說明時都只取8個位元來說明,但實際的位元在運算時,需依資料型態所佔的記憶體長度而定,例如在使用int型態的0作運算時,要考慮的是32個位元,而不是只有8個位元,因為int佔有4個位元組。

在位元運算上,C還有左移(<>)兩個運算子,左移運算子會將所有的位元往左移指定的位數,左邊被擠出去的位元會被丟棄,而右邊會補上0;右移運算則是相反,會將所有的位元往右移指定的位數,右邊被擠出去的位元會被丟棄,至於左邊位元補0或補1則不一定,視系統而定。

可以使用左移運算來作簡單的2次方運算示範,如下所示: #include intmain(void){ intnum=1; printf("2的0次:%d\n",num); num=num<<1; printf("2的1次:%d\n",num); num=num<<1; printf("2的2次:%d\n",num); num=num<<1; printf("2的3次:%d\n",num); return0; } 執行結果如下: 2的0次:1 2的1次:2 2的2次:4 2的3次:8 實際來左移看看就知道為何可以如此運算了: 000000011 000000102 000001004 000010008



請為這篇文章評分?