• 位运算之清除特定的某几位


    在C语言中,一个32位的整数能表征32种状态。那么,要将某几种特定的状态清除掉,也就是将整数对应的某几位清除掉,有固定套路吗? Absolutely yes! 固定套路如下:

    FLAGS &= ~( X | Y | Z )
    
    /*
     * 1. N      = X | Y | Z;
     * 2. M      = ~N;
     * 3. FLAGS &= M;
     */

    1. 将特定的某几位对应的整数X, Y, Z使用或(|)运算组合成一个新的整数N;
    2. 将新的整数N按位取反(~),得到新的整数M;
    3. 以M为基,对FLAGS进行与(&)运算。

    注意每一个特定的位都对应一个特定的整数。特定的整数诸如X, Y, Z是如何被定制的,以及上面的套路是如何被实施的,下面将给出一个具体的例子予以说明。

    o foo.c

     1 #include <stdio.h>
     2 
     3 /*
     4  *                 +---+---+---+---+---+---+---+---+
     5  *                 |8th|7th|6th|5th|4th|3rd|2nd|1st|
     6  * +---------------+---+---+---+---+---+---+---+---+
     7  * | INDEX         | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
     8  * +---------------+---+---+---+---+---+---+---+---+
     9  * | SF_ATTENTION  | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
    10  * | SF_INPROGRESS | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
    11  * | SF_OK         | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
    12  * | SF_ERR        | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
    13  * | SF_TIMEOUT    | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
    14  * | SF_USYNC      | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
    15  * | SF_XXX        | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
    16  * | SF_YYY        | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
    17  * +---------------+---+---+---+---+---+---+---+---+
    18  */
    19 
    20 #define SF_ATTENTION            001 /* entry needs servicing */
    21 #define SF_INPROGRESS           002 /* sync is in progress */
    22 #define SF_OK                   004 /* sync has happend successfully */
    23 #define SF_ERR                  010 /* sync has happend unsuccessfully */
    24 #define SF_TIMEDOUT             020 /* proc timed out in sync event */
    25 #define SF_USYNC                040 /* entry is a user sync, else auto */
    26 
    27 /**
    28  * OR (2) define as (1 << N):
    29  *
    30  * #define SF_ATTENTION         (1 << 0)
    31  * #define SF_INPROGRESS        (1 << 1)
    32  * #define SF_OK                (1 << 2)
    33  * #define SF_ERR               (1 << 3)
    34  * #define SF_TIMEDOUT          (1 << 4)
    35  * #define SF_USYNC             (1 << 5)
    36  *
    37  * OR (3) define as Hex:
    38  *
    39  * #define SF_ATTENTION         0x01
    40  * #define SF_INPROGRESS        0x02
    41  * #define SF_OK                0x04
    42  * #define SF_ERR               0x08
    43  * #define SF_TIMEDOUT          0x10
    44  * #define SF_USYNC             0x20
    45  */
    46 
    47 /*
    48  * If there is an int flags, we want to clear its specified bits to be zero,
    49  * we will use
    50  *     flags &= ~(... | ... | ...)
    51  *
    52  * e.g. clear the 3rd, 4th and 5th bits to be 0
    53  *      flags &= ~(SF_OK | SF_ERR | SF_TIMEDOUT);
    54  */
    55 
    56 /*
    57  * XXX: _NOTE is from /usr/include/sys/note.h of Solaris
    58  *            note.h: interface for annotating source with info for tools
    59  */
    60 #ifndef _NOTE
    61 #define _NOTE(s)
    62 #endif
    63 
    64 int
    65 main(int argc, char *argv[])
    66 {
    67         unsigned char flags = SF_ATTENTION | SF_OK | SF_USYNC;
    68 _NOTE(                87654321 )
    69 _NOTE(                -------- )
    70 _NOTE(flags == 045 == 00100101b)
    71         printf("a) flags = 0%o
    ", flags);
    72 
    73 _NOTE(flags   &= ~(bit#3 | bit#4  | bit#5))
    74         flags &= ~(SF_OK | SF_ERR | SF_TIMEDOUT);
    75 
    76 _NOTE(                87654321 )
    77 _NOTE(                -------- )
    78 _NOTE(flags == 041 == 00100001b)
    79         printf("b) flags = 0%o
    ", flags);
    80 
    81         return flags;
    82 }

    o 编译并运行

    $ gcc -g -Wall -m32 -std=c99 -o foo foo.c
    
    $ ./foo
    a) flags = 045
    b) flags = 041
    
    $ echo $?
    33

    针对L67,L74这两行的位运算过程,做出如下剖析:

    67         unsigned char flags = SF_ATTENTION | SF_OK | SF_USYNC;
    74         flags &= ~(SF_OK | SF_ERR | SF_TIMEDOUT);
    
    L67: flags = | SF_ATTENTION  | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
                +| SF_OK         | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
                +| SF_USYNC      | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
               =                 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 1 |
    
    L74:  (SF_OK | SF_ERR | SF_TIMEDOUT)
               = | SF_OK         | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
                +| SF_ERR        | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
                +| SF_TIMEOUT    | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
               =                 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 |
    
         ~(SF_OK | SF_ERR | SF_TIMEDOUT)
               =                 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 1 |
    
         flags & ~(SF_OK | SF_ERR | SF_TIMEDOUT)
               =                 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 1 |
                                &| 1 | 1 | 1 | 0 | 0 | 0 | 1 | 1 |
               =                 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 |
               = | SF_ATTENTION  | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
                +| SF_USYNC      | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |

    由此可见,构造一个某几个特定的位为0但是其他所有位都为1的整数是整个运算过程的关键所在

    那么,这一固定套路有什么实际的用处呢? 当然用处是大大的,只要涉及到状态机的切换,就不可避免地要将某一个或者某几个特定的状态清除掉。例如: linux-4.9.16/kernel/printk/printk.c#2557

     总结:

    清除整数的某几位的套路 : FLAGS &= ~( X | Y | Z )
    设置整数的某几位的套路 : FLAGS |=  ( X | Y | Z )

     APPENDIX: Get the Nth bit of an Integer

    hd$ cat /tmp/a.py 
    #!/usr/bin/python3
    
    def get_bit(n, m):
        return ((n & (1 << m)) >> m)
    
    for i in [0, 1, 2, 4, 8, 16, 32, 64]:
        for j in range(8):
            print("int = %2d, pos = %d, bit=%d" % (i, j+1, get_bit(i, j)))
        print()
    
    hd$
    /tmp/a.py int = 0, pos = 1, bit=0 int = 0, pos = 2, bit=0 int = 0, pos = 3, bit=0 int = 0, pos = 4, bit=0 int = 0, pos = 5, bit=0 int = 0, pos = 6, bit=0 int = 0, pos = 7, bit=0 int = 0, pos = 8, bit=0 int = 1, pos = 1, bit=1 int = 1, pos = 2, bit=0 int = 1, pos = 3, bit=0 int = 1, pos = 4, bit=0 int = 1, pos = 5, bit=0 int = 1, pos = 6, bit=0 int = 1, pos = 7, bit=0 int = 1, pos = 8, bit=0 int = 2, pos = 1, bit=0 int = 2, pos = 2, bit=1 int = 2, pos = 3, bit=0 int = 2, pos = 4, bit=0 int = 2, pos = 5, bit=0 int = 2, pos = 6, bit=0 int = 2, pos = 7, bit=0 int = 2, pos = 8, bit=0 int = 4, pos = 1, bit=0 int = 4, pos = 2, bit=0 int = 4, pos = 3, bit=1 int = 4, pos = 4, bit=0 int = 4, pos = 5, bit=0 int = 4, pos = 6, bit=0 int = 4, pos = 7, bit=0 int = 4, pos = 8, bit=0 int = 8, pos = 1, bit=0 int = 8, pos = 2, bit=0 int = 8, pos = 3, bit=0 int = 8, pos = 4, bit=1 int = 8, pos = 5, bit=0 int = 8, pos = 6, bit=0 int = 8, pos = 7, bit=0 int = 8, pos = 8, bit=0 int = 16, pos = 1, bit=0 int = 16, pos = 2, bit=0 int = 16, pos = 3, bit=0 int = 16, pos = 4, bit=0 int = 16, pos = 5, bit=1 int = 16, pos = 6, bit=0 int = 16, pos = 7, bit=0 int = 16, pos = 8, bit=0 int = 32, pos = 1, bit=0 int = 32, pos = 2, bit=0 int = 32, pos = 3, bit=0 int = 32, pos = 4, bit=0 int = 32, pos = 5, bit=0 int = 32, pos = 6, bit=1 int = 32, pos = 7, bit=0 int = 32, pos = 8, bit=0 int = 64, pos = 1, bit=0 int = 64, pos = 2, bit=0 int = 64, pos = 3, bit=0 int = 64, pos = 4, bit=0 int = 64, pos = 5, bit=0 int = 64, pos = 6, bit=0 int = 64, pos = 7, bit=1 int = 64, pos = 8, bit=0
  • 相关阅读:
    【资源分享】一个匿名文件分享网站
    【C语言】指针到底有什么用
    【C语言】一招搞定C语言各种复杂指针
    【资源分享】Visual Studio全版本在线安装包(5MB)
    【资源分享】C语言也能干大事(第二版)
    【资源分享】迅雷
    Nuxt spa deploy
    nginx ssl docker
    Linux查看环境变量
    Nginx 配置
  • 原文地址:https://www.cnblogs.com/idorax/p/6575341.html
Copyright © 2020-2023  润新知