我看iOS自己定義的枚舉裏面常常會使用左移(<<)來定義枚舉的值,一開始我還不懂爲啥要這麼定義。這麼處理的邏輯跟iOS系統不要緊。bash
定義:ui
typedef enum{
a = 1 << 0,
b = 1 << 1,
c = 1 << 2,
d = 1 << 3
}testEnum;
複製代碼
使用:spa
testEnum e = a | b;
if (e & a) {
printf("知足條件a");
//知足a要作的事
}
if (e & b) {
printf("知足條件b");
//知足b要作的事
}
if (e & c) {
printf("知足條件c");
//知足c要作的事
}
複製代碼
爲何枚舉值定義成1左移n位的形式呢?看枚舉值的二進制形式:code
規律就是隻有一個位上爲1,但其餘爲都爲0.這樣 e = a | b,二進制形式就是00000011,而後e & b的時候,由於位與(&)的性質,只有都爲1纔會是1,這樣e & a和e & b都會有值,不是0,也就爲true。string
用移位來定義枚舉就是爲了把1的位置錯開,而後當你須要同時知足多個枚舉值的時候,可使用位或(|)操做把多個枚舉值合併,而不會互相影響。好比 00010000 和 00100000合併,他們的1位置是錯開的,合併以後1的位置都保留下來了,變成00110000. 而後使用位與(&)來檢測某個位上的1,由於每一個枚舉值只有一個位上是1,除非你的位上也是1,不然位與操做後就爲0了。好比0010000和00010000位與就爲0;而00100000和00110000位與就不是0。而前面位或操做又能夠把每一個枚舉值的1都保留了,因此後面位與操做會把它包含的每一個枚舉值都體現出來。class
也就是若是e = a| b | c | d,那麼e & a 、e & b 、e & c 、 e & d都爲true.就是你這個枚舉值包含了那些原始枚舉值,&操做值都爲true.這樣代碼寫起來,邏輯就符合人的思惟了。test
不知道這個是否是常識,我大學不是計算機專業,也沒人跟我專門講過這個。基礎
上面是使用了2進制來錯開,保留每一個位,其實其餘進制也能夠,但位數是2的n次方。 好比0000 0000 8個位,能夠前4個位存儲一個值,後4個位存儲一個值:變量
typedef enum{
a = 0 << 0,
b = 1 << 0,
c = 2 << 0,
d = 3 << 0,
e = 0 << 4,
f = 1 << 4,
g = 2 << 4,
h = 3 << 4
}testEnum;
複製代碼
這裏的話,a b c d的前4爲都是0,值的變化在後4位,而e f g h正好相反。若是你使用 a b c d內的值位或操做,是無法保存二者的,好比一個數是0000 0011,它能夠是d,也能夠是d | b,無法判斷是否含有枚舉b,由於1和3的最後一位都是1,一個數末位是1,你不知道這個1是從哪一個枚舉值帶來的。二進制
因此這樣定義a b c d之間是無法共存的。可是a b c d中任何一個均可以和e f g h中任何一個共存。由於它們值存的位置不同。
這種枚舉舉個例子,好比使用枚舉給一個蘋果指定類型,a b c d能夠是4中不一樣產地,e f g h 能夠是不一樣的品種,你看產地只能有一個、品種也只能有一個,可是品種和產地是能夠共存的。
在上面一段的基礎上看應用實例,反過來再某個使用環境下怎麼定義枚舉?個人理解是要分層。
好比有a b c是不可共存的,那好,把他們定義成0 1 2 3 ,而後它們只會佔2個位,由於3最大,是0000 00 11,那麼接下來其餘的枚舉值就能夠左移2個位來和他們避開。而後 d e是不可共存的,那麼就把d e 定義爲 0 << 2和1<< 2。注意:a b c 分紅第一組,d e分紅第二組的意思,除了組內不可共存,也表明組之間能夠共存,這就是我說分層的意思。照着這個邏輯就能夠把複雜的共存和不共存的相互關係捋清,而後分別定義枚舉。組之間的取值區域不能重疊,組之間能夠。
typedef enum{
a = 0 << 0,
b = 1 << 0,
c = 2 << 0,
d = 0 << 2,
e = 1 << 2,
f = 0 << 3,
g = 1 << 3,
h = 2 << 3
}testEnum;
複製代碼
好比有個物品A有10個不一樣的屬性,每一個屬性都有7個之內的取值,即有屬性a b c d e f g h i j,而後a有5個可能取值,b有4個可能取值,c有7個可能取值,等等。按理說,須要10個變量來保存,但其實能夠一個數就搞定,讓N = a + b * 7 + c * 7的平方 + d * 7的立方 + ...,反之,知道一個數,把它用7進製表示,從低到高就是a b c d ...的值了。