位元運算子& AND, | OR, ^ XOR, ~ NOT @ 程式手扎 - 隨意窩

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

邏輯運算子電路中最基本的邏輯運算子如下所列,可說是工程人員都耳熟能詳地,假設有A 和B 兩個bit,即它們的值只有0 和1 兩種,那麼A AND B 只有在兩者皆為1 的時候才 ... 程式手扎一些程式心得日誌相簿影音好友名片 關於我加入好友我的相簿我的影音 全部展開|全部收合 關鍵字 tsai.oktomy's新文章位元運算子&AND,|OR,^XOR,~NOTconst放置位置的意義SomecurrentinternallimitsofBDEC++的基本資料型態MFC程式結構基礎標準C++的類型轉換:static_cast、dynamic_castC/C++格式化#pragma設定Compiler模式關鍵詞__cplusplusextern"C"真實意義探討C++中extern“C”含義 tsai.oktomy's新回應沒有新回應! 巨人的肩膀程式手扎Tomy盤中日記 我的相簿 201303291406位元運算子&AND,|OR,^XOR,~NOT?C++  邏輯運算子 電路中最基本的邏輯運算子如下所列,可說是工程人員都耳熟能詳地,假設有A和B兩個bit,即它們的值只有0和1兩種,那麼AANDB只有在兩者皆為1的時候才會1,AORB則是兩者有ㄧ者為1的時候就會1,而AXORB是A與B不相等的時候為1,NOT則是單純地0變 1、1變0。

>>位元運算子  是將數值的位元向右移動n個位元。

向右移動後,超出儲存範圍的數字捨去,而左邊多出的位元就補上0。

  <> 位元左移 位元右移 6 > >= < <= 比較運算大於 比較運算大於等於 比較運算小於 比較運算小於等於 7 == != 比較運算等於 比較運算不等於 8 & ^ | 位元運算AND 位元運算XOR 位元運算OR 9 && || 邏輯運算AND 邏輯運算OR 10 ?: 條件運算子 11 = 指定運算   而C/C++的位元處理運算子也是如此,不同的是這些運算子可以一次處理多個位元,例如unsignedchar有8bits,那麼: unsignedchara=205(十進位)=11001101(二進位) unsignedcharb=158(十進位)=10011110(二進位) aANDb:c=a&b=140(十進位)=10001100(二進位) 在這個例子當中的&運算子就是C/C++的AND位元運算子,從這個例子可以看到&運算子分別對unsignedchar的8bits做了AND位元運算。

在之前你已經看過&出現在別的地方,其實習慣的話並不容易搞混的: if(a!=0&&b!=0){...}//連續兩個&&是邏輯判斷的AND if(a&&b){...}//同上 if(a&b){...}//這是AND位元運算,如果abitwise-ANDb的結果不為零... char*ptr=&a;//&當一元運算子的時候是對變數取位址  總之C/C++有這四種位元運算子,可用於任何資料型別,意即該型別有幾個bits就做幾個bits的運算: 意義 運算子 範例 a b c AND & c=a&b 11001101 10011110 10001100 OR | c=a|b 11001101 10011110 11011111 XOR ^ c=a^b 11001101 10011110 01010011 NOT ~ c=~a 11001101   00110010 2進位,10進位,16進位 請注意2進位/10進位/16進位只是(撰寫程式碼)的時候表示數值的格式,不是電腦儲存數值的格式。

電腦儲存數值一定是bitbybit的、也可以說一定是2進位的,但是了解不同進位之間的換算與表示法,仍然對寫程式大有幫助。

當我們說一個數字是205的時候,事實上我們經常隱喻了它是個10進位數字,我們之所以把這個數字寫成"205"是因為: 205(10進位)=2x102+0x101+5x100=cx161+dx100(16進位)=1x27+1x26+0x25+0x24+1x23+1x22+0x21+1x20(2進位) 如這個例子所示,我們所謂的2進位/10進位/16進位意思就是以2/10/16為底,所以205這個數字以16進位應該表示成cd,以2進位應該表示成11001101,把0~15之間的數以2進位/10進位/16進位列出如下表,其中16進位(Hex)以a~f代表10~15。

Dec Hex Binary Dec Hex Binary 0 0 0000 8 8 1000 1 1 0001 9 9 1001 2 2 0010 10 a 1010 3 3 0011 11 b 1011 4 4 0100 12 c 1100 5 5 0101 13 d 1101 6 6 0110 14 e 1110 7 7 0111 15 f 1111 為甚麼要學習2進位與16進位呢?從這個表上你可以清楚地見到16進位每一個數字就恰恰好代表了4bits,例如0xcd=11001101:c(16進位)=1100(2進位)d(16進位)=1101(2進位) 所以我們只要一看到一個以16進位的數值,很直覺地就可以知道這個數字的各bit為何,因此在程式中以16進位來表示要進行位元運算(bitwiseoperation)的數字是非常方便的,否則就得換算了。

要在2進位/10進位/16進位之間換算,其實最佳的工具就是Windows內附的小算盤(calc.exe),如下圖,首先在檢視選單下,將小算盤切換到「工程型」,然後這個程式就會多出下圖密密麻麻的按鈕,接著選擇你要輸入數字的數值進制並且輸入數值,例如我要輸入10進位的205,所以我選擇了「十進位」然後輸入205,然後只要點選其他的數值進制,顯示的數字就會變成別的進制,例如在圖中我點選十六進制,205就變成了CD,點選了二進位,205就變成了11001101。

在C語言當中沒有二進位表示法與顯示格式,所以你沒辦法在程式東打一大串1001010101010101以二進位來指定數值,但是有16進位的表示法,也就是說你可以把你要運算的位元每4個為一組,以一個16進位的數字表示。

C語言的16進位表示法就是在數值前加上0x前綴字,編譯器變知道這個數值是16進位不是10進位,例如: a=0xcd;//和a=205是一樣的 而printf()或其他的字串格式化與顯示函式都有16進位的顯示格式,就是%x(小寫顯示)或%X(大寫顯示)格式字串關鍵字,例如: printf("%x",a);//顯示cd printf("%X",a);//顯示CD 位元運算範例 下面這個例子展示了C語言中四種位元運算子的使用方法,請注意註解中的執行結果c,和原始數值a與b比較,就可知道這些運算子的效果。

#include voidmain(void) { //以下分別以進位與進位表示法來指定a與b:unsignedchara=205;//即11001101,相當於a=0xcd unsignedcharb=0x9e;//即10011110,相當於b=158 //試用AND運算子,得到c=0x8c即10001100unsignedcharc=a&b; printf("%xAND%x=%x\n",a,b,c); //試用OR運算子,得到c=0xdf即11011111c=a|b; printf("%xOR%x=%x\n",a,b,c); //試用XOR運算子,得到c=0x53即01010011c=a^b; printf("%xXOR%x=%x\n",a,b,c); //試用NOT運算子,得到c=0x32即00110010c=~a; printf("NOT%x=%x\n",a,c); } 執行結果 cdAND9e=8c cdOR9e=df cdXOR9e=53 NOTcd=32 當你的資料不止1byte(8bits) 的時候也一樣,這些運算子是有幾個bit就運算幾個bit,如下面例子是unsignedint(32bits)的例子,用16進位表示法去指定數值,可以見得同樣每個16進位數值都代表了4bits。

0x9527(16進位)=(二進位) 00000000000000001001010100100111 (00009527} 0xff00(16進位)=(二進位) 00000000000000001111111100000000 (0000ff00) 範例: unsignedintx=0x9527; unsignedinty=0xff00; unsignedintq=x&y; printf("%xAND%x=%x\n",x,y,q); 執行結果 9527ANDff00=9500 位元運算的應用 到這裡你可能會問,這些位元運算有甚麼用途呢?其實用途很多,比方說,例用AND運算子「a與b均為1的時候才會1」的性質,換言之「如果b為0的話,a不論多少、aANDb必定為0」,另一方面如果b為1,那麼aANDb就等於是a的原值,利用這個性質,就可以以b做為a的遮罩(mask),或稱做過濾器。

位元的AND運算非常地常用,在下圖中的黑白點陣圖(bitmap)影像,每個bit代表一個黑白像素(pixel),所以每個byte代表8bits,你可以看到左邊的影像是個V字,右邊的遮罩影像是個圓形。

把這兩個影像每個byte做AND的結果如下所示,等於是把V影像剪裁(crop)在圓形範圍之內了,所以V的兩支銳角不見了。

利用這個技巧,可以用AND去裁切掉影像不要的部分。

AND的運算的一個常見用途則是用在權限管理上,所謂使用者a對物品b的權限,應當是「a有權限使用物品、而b剛也有開放被使用的權限」的時候,a才得以使用b物品,如果a有使用物品的權限但是b不是公開物品,那麼a無法使用b物品,換言之,如果b是公開物品,但是a沒有使用任何物品的權限(比如權限等級只是訪客等級),a也不能使用b物品,所以很顯然地「a是否有權限使用物品b」是一個AND運算,舉個例子來說: 使用者OpenJohn的權限bits:00010011 意義000xxxxx→notowner xxx100xx→可讀group文件 xxxxxx11→可讀寫公開文件 而 某檔案7-11.doc的權限遮罩:11111100 意義111xxxxx→owner可讀寫刪 xxx111xx→同group可讀寫刪 xxxxxx00→訪客不可讀不可寫 所以 OpenJohn對於7-11.doc的權限=AND結果:00010000 意義000xxxxx→notowner xxx100xx→可讀此文件 xxxxxx00→不可讀寫此文件 這個技巧普遍地被各作業系統應用於使用者登入權限與檔案/目錄存取權限的管理與判讀。

除了AND運算以外,OR運算的特質在於「a與b只要有1者為1則a|b必定為1」,若b為0,則a|b則為a的原值,所以可說OR運算有「重疊」或「加法」的效果,相對於AND運算用於剪裁影像或判斷權限,OR運算則用於「影像重疊」或「賦予權限」,類似地,NOT運算可用於「影像反白」或「取得排除權限」或「取得遮罩」影像。

比較特別的是XOR運算,他的特色是「a和b不同的時候a^b才1,否則a^b必為0」,所以(a^b)^b等於a自己,以影像處理來說,A影像對B影像做XOR,會把B影像重疊在A之上(但是部分像素會反白),然後再對同一張B影像做一次XOR則能夠恢復A的原貌,所以XOR可以做到影像的「暫時」重疊(或移動中的影像),從前經常用於簡單動畫、滑鼠游標或輔助線的顯示上。

 oktomy/Xuite日誌/回應(0)/引用(5)/好文轉寄沒有上一則|日誌首頁|沒有下一則回應



請為這篇文章評分?