位运算和枚举

我看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 是00000001
  • 1 << 1 是00000010
  • 1 << 2 是00000100

规律就是只有一个位上为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;
复制代码
四、最后,我以为这个思想在使用任何数作基数都适用,只是计算机的位操做让2变得特别。

好比有个物品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 ...的值了。

相关文章
相关标签/搜索