枚舉、按位與或運算、位移的簡單應用,枚舉運算位移應用
當我們在寫程式的時候,經常會遇到各種各樣的設定,比如設定視窗的四條邊的停靠狀態(比如上邊是否停靠在父控制項的上邊上、左邊是否停靠在父控制項的左邊上、右邊是否停靠在父控制項的右邊上、底邊是否停靠在父控制項的底邊上。
方案1
或許你想到的第一個答案是設定四個BOOL值,用C語言實現的代碼或許是這樣的。
#include <stdio.h>typedef char BOOL;#define True 1#define False 0int main(int argc, const char * argv[]) { //定義 BOOL isTop; BOOL isLeft; BOOL isRight; BOOL isBottom; //賦值 isTop = True; isLeft = False; isRight = True; isBottom = False; //使用 printf("%d\n",isTop); printf("%d\n",isLeft); printf("%d\n",isRight); printf("%d\n",isBottom); return 0;}
這是一種最常用的方式,但是這種只是最笨的一種方式,因為你需要4值來實現整段邏輯。最笨,最常用,但是這也最簡單、最容易理解,但是在賦值的時候相對來說你要寫四遍。
方案2
如果你熟悉記憶體中資料的儲存格式和按位與或運算,你或許會想到這樣來解決掉這個問題,對於你這樣賦值相對會容易很多
#include <stdio.h>#define isDockTop(dock) isDock(dock,isTop)#define isDockLeft(dock) isDock(dock,isLeft)#define isDockRight(dock) isDock(dock,isRight)#define isDockBottom(dock) isDock(dock,isBottom)typedef char BOOL;typedef enum{ isTop = 1, isLeft = 2, isRight = 4, isBottom = 8} Dock;#define True 1#define False 0BOOL isDock(Dock dock,Dock dockTo){ return (dock & dockTo) > 0;}int main(int argc, const char * argv[]) { //定義 char dock; //賦值 dock = isTop | isRight; //使用 printf("isTop\t%d\n",isDockTop(dock)); printf("isLeft\t%d\n",isDockLeft(dock)); printf("isRight\t%d\n",isDockRight(dock)); printf("isBottom\t%d\n",isDockBottom(dock)); return 0;}
可能對於這個編碼風格大家還是相對熟悉一些的,因為在賦值的時候,可能會經常的看到這種按位與運算賦值,因為這個賦值實在是太方便了。關於那個枚舉的值為什麼這麼寫呢?因為C語言中通用的記憶體資料儲存的原因,深層次的原因,我就不在此贅述。因為這個太基礎了。
或許你現在覺得這個玩意還行,但是枚舉的值,太難寫了。或許,我們可以通過以下寫法來讓枚舉變得相對簡單一些
typedef enum{ isTop = 0B0001, isLeft = 0B0010, isRight = 0B0100, isBottom = 0B1000} Dock;
直接將二進位的數字寫到檔案裡邊,Char只有8個bit的還好說一些,但是像int這種有32bit的,早就眼花了把。或許我們可以通過位移來快速方便的解決掉這個問題。
方案2最終版
#include <stdio.h>#define isDockTop(dock) isDock(dock,isTop)#define isDockLeft(dock) isDock(dock,isLeft)#define isDockRight(dock) isDock(dock,isRight)#define isDockBottom(dock) isDock(dock,isBottom)typedef char BOOL;typedef enum{ isTop = 1, isLeft = 1 << 1, isRight = 1 << 2, isBottom = 1 << 3} Dock;#define True 1#define False 0BOOL isDock(Dock dock,Dock dockTo){ return (dock & dockTo) > 0;}int main(int argc, const char * argv[]) { //定義 char dock; //賦值 dock = isTop | isRight; //使用 printf("isTop\t%d\n",isDockTop(dock)); printf("isLeft\t%d\n",isDockLeft(dock)); printf("isRight\t%d\n",isDockRight(dock)); printf("isBottom\t%d\n",isDockBottom(dock)); return 0;}
標誌枚舉中 按位或運算的理解
你的按位或的結果確實只有一個,但是卻有兩個位被置位了啊。
這個toString是調用預設的toString,所以會使用G格式來顯示。
因為你設定了[Flags]標誌,所以會根據多個位把結果組合起來顯示,返回用分隔字元分隔的這些常數名稱的列表
MSDN裡面對於G格式的描述:
======================================================
如果value等於某個已命名的枚舉常數,則返回該常數的名稱;否則返回value的等效十進位數。
例如,假定唯一的枚舉常數命名為“Red”,其值為 1。如果將value指定為 1,則此格式返回“Red”。然而,如果將value指定為 2,則此格式返回“2”。
- 或 -
如果將FlagsAttribute自訂屬性應用於枚舉,則value將被視為位域,該位域包含一個或多個由一位或多位組成的標誌。
如果value等於已命名的枚舉常數的組合,則返回用分隔字元分隔的這些常數名稱的列表。將在value中搜尋標誌,從具有最大值的標誌到具有最小值的標誌進行搜尋。對於與value中的位域相對應的每個標誌,常數的名稱串連到用分隔字元分隔的列表。則將不再考慮該標記的值,而繼續搜尋下一個標誌。
如果value不等於已命名的枚舉常數的組合,則返回value的等效十進位數。
========================================================
對於JAVA 中的位移運算>>
char的範圍是0~65535.用2進位表示,就是0000 0000 0000 0000到1111 1111 1111 1111
byte的範圍是-128~127.用2進位表示,就是1000 0000到0111 1111.
看到了麼,一個char要用兩個byte才能存下來。
例如假設cData=1101 0101 0001 0001:
>>8就是說,右移8個bit,二進位的.右移8bit,那個1101 0101就往右移動8位。因為首位是1,所以前面全部補1,得到1111 1111 1101 0101.然而這時候,想得到的是1101 0101,而不需要前面那8個1,所以用0xff&來處理。0xff就是0000 0000 1111 1111,&就是這個bit在兩個運算元都是1的情況下使答案bit為1,就是是取後8個bit。所以0000 0000 1111 1111 & 1111 1111 1101 0101=0000 0000 1101 0101.這樣,就取得了cData的前8bit.存入bData[0].
>>0無運算,只是寫著好看的。0xff&cData直接取後8bit,這個例子裡,就是說0000 0000 1111 1111 & 1101 0101 0001 0001=0000 0000 0001 0001.這樣,就取得了cData的後8bit.存入bData[1].