为什么要通过 mask 的位运算才能判断 flag - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
fhj
V2EX    Android

为什么要通过 mask 的位运算才能判断 flag

  •  1
     
  •   fhj 2022-12-04 18:29:33 +08:00 11827 次点击
    这是一个创建于 1041 天前的主题,其中的信息可能已经有所发展或是发生改变。

    public static final int VISIBLE = 0x00000000;

    public static final int INVISIBLE = 0x00000004; public static final int GOnE= 0x00000008; static final int VISIBILITY_MASK = 0x0000000C; 判断 flags 时是这么判断的:i ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) 为什么不这样判断:if ((child.mViewFlags & VISIBLE) == VISIBLE) 
    15 条回复    2022-12-05 11:53:11 +08:00
    yongfrank
        1
    yongfrank  
       2022-12-04 18:34:21 +08:00   1
    刚刚用 ChatGPT 出了一个答案

    在计算机程序中,通过 mask 的位运算来判断 flag 通常是为了将 flag 的多个属性(例如是否启用、是否可读、是否可写等)用一个整数来表示。

    在位运算中,通过与掩码( mask )进行与(&)运算可以判断 flag 的某一位是否被设置为 1 。例如,如果要判断 flag 的第 3 位是否被设置为 1 ,可以将 flag 与掩码 0b100 进行与运算,如果结果为 0 则表示 flag 的第 3 位被设置为 0 ,否则表示 flag 的第 3 位被设置为 1 。

    使用 mask 的位运算来判断 flag 的好处在于它可以节省存储空间,将多个属性用一个整数来表示,而不需要单独开辟多个变量来存储每个属性。例如,如果使用多个变量来表示 flag 的多个属性,则需要开辟多个 8 位的存储空间,而如果使用 mask 的位运算,则只需要开辟一个 8 位的存储空间就可以表示多个属性。
    hello2090
        2
    hello2090  
       2022-12-04 18:34:47 +08:00
    你这个 if ((child.mViewFlags & VISIBLE) == VISIBLE) 不是 永远 true 吗?
    fhj
        3
    fhj  
    OP
       2022-12-04 18:37:40 +08:00
    @hello2090 mViewFlags 没有设置不就是 false 了吗
    Cat7373
        4
    Cat7373  
       2022-12-04 18:39:19 +08:00
    @hello2090 #2 并不是的,MASK 说明了 0x0C 这一位表示是否可视,VISIBLE 的值说明了这一位是 0 时是可视,是 1 时是不可视,即 MASK 表示哪一位代表这个开关,VISIBLE 表示值是什么的时候代表什么结果
    fhj
        5
    fhj  
    OP
       2022-12-04 18:40:06 +08:00
    @yongfrank 谢谢,刚才看到一段这样的代码,这或许就是 mask 的作用把
    switch (mViewFlags&VISIBILITY_MASK) {
    case VISIBLE: out.append('V'); break;
    case INVISIBLE: out.append('I'); break;
    case GONE: out.append('G'); break;
    default: out.append('.'); break;
    }
    cxtrinityy
        6
    cxtrinityy  
       2022-12-04 18:40:40 +08:00
    VISIBILITY_MASK 是 0x0000000C -- 二进制是 1100
    invisible 是 0x00000004 -- 二进制是 0100
    gone 是 0x00000008 -- 二进制是 1000
    也就是 gone 和 invisible 是用不同位来表示, visible 要保证 gone 和 invisible 都未设置 一次位运算就能验证两个设置
    Cat7373
        7
    Cat7373  
       2022-12-04 18:41:29 +08:00
    @Cat7373 #4 修正一下,0x0C 有两个 bit 位为 1 ,因此这两个 bit 位任意一个为 1 ,此判断结果都为不可视,均为 0 ,才为可视,具体代码设计中,这两个 bit 位各代表什么意思这里看不出,但设计上可以实现,有两个各代表某个意思的开关,任意一个打开,都代表不可视
    Cat7373
        8
    Cat7373  
       2022-12-04 18:42:03 +08:00
    @cxtrinityy #6 啊这,没注意到上面两个常量,丢人了丢人了
    viggoc
        9
    viggoc  
       2022-12-04 18:43:27 +08:00   1
    @fhj #3 任何数 & 0x00000000 不都是 0x00000000 吗
    fhj
        10
    fhj  
    OP
       2022-12-04 18:47:06 +08:00
    @viggoc 那应该是默认是 0,有其他需要再设置就好了
    DeweyReed
        11
    DeweyReed  
       2022-12-04 18:48:15 +08:00
    public static final int VISIBLE = 0x00000000;
    jeesk
        12
    jeesk  
       2022-12-04 21:58:02 +08:00
    最近自己优化内存用到的代码直接贴出来给你了。
    ```
    object BitStatesUtils {
    const val isFavorite = (1L shl 0).toByte()
    const val isDownload = (1L shl 1).toByte()
    const val isTrashed = (1L shl 2).toByte()

    public const val SIZE_BITS: Byte = 0

    /**
    * @param states 所有状态值
    * @param value 需要判断状态值
    * @return 是否存在
    */
    fun hasState(states: Byte, value: Byte): Boolean {
    val byte = (states and value) as Byte
    return byte != SIZE_BITS
    }

    fun Byte.HasState(value: Byte): Boolean {
    return BitStatesUtils.hasState(this, value)
    }

    /**
    * @param states 已有状态值
    * @param value 需要添加状态值
    * @return 新的状态值
    */
    fun addState(states: Byte, value: Byte): Byte {
    return if (hasState(states, value)) {
    states
    } else (states or value)
    }

    fun Byte.AddState(value: Byte): Byte {
    return addState(this, value)
    }

    /**
    * @param states 已有状态值
    * @param value 需要删除状态值
    * @return 新的状态值
    */
    fun removeState(states: Byte, value: Byte): Byte {
    returnif (!hasState(states, value)) {
    states
    } else (states xor value)
    }


    }
    ```
    FranzKafka95
        13
    FranzKafka95  
       2022-12-04 23:04:47 +08:00 via Android
    嵌入式里很常见的操作,尤其是当你需要用一个 bit 表示一个状态,同时又想节省空间时,位操作就非常有必要了。
    Building
        14
    Building  
       2022-12-04 23:11:22 +08:00 via iPhone
    Mask 和 Optional Value 就像锁和钥匙,你可以把运算过程想像成把钥匙插入锁里面,全部凹槽都配平才能打开
    lysS
        15
    lysS  
       2022-12-05 11:53:11 +08:00
    用位表示 flag ,是为了正交隔离
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5576 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 07:12 PVG 15:12 LAX 00:12 JFK 03:12
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86