将m位设置为n位

时间:2013-04-10 05:14:04

标签: c bit-manipulation

我有一个32-bit号码而不使用for循环,我想将m设置为 n位。

例如:

m位可以是2nd5th9th10th
 n位可以是22nd2711th位。

我假设(m

请帮助我。谢谢

1 个答案:

答案 0 :(得分:9)

虽然问题已经结束,但我不确定我的旧答案。我已经更新了经过测试的代码。希望将来对某人有所帮助。

假设位从LSB到MSB编号:

BIT NUMBER    31                                     0
               ▼                                     ▼
number bits    0000 0000 0000 0000 0000 0000 0001 0101 
               ▲    ^           ^                    ▲ 
              MSB   |           |                   LSM
                    |           | 
                   n=27        m=17

LSB - Least Significant Bit (numbered 0)
MSB - Most  Significant Bit (numbered 31) 

上图中,我已经说明了位从LSB到MSB的编号方式。 请注意nm的相对位置n > m


将所有位从n设置为m


设置 - 1 从位置 m n 的所有位(其中{ {1}})以32位数字表示。 您需要一个32位掩码,其中所有位都从n > m1 n 位是 m

例如,要将所有位从 0 设置为 m=17 ,我们需要掩码,如:

n=27

如果我们有任何32位数字,按位数OR( BIT NUMBER 31 n=27 m=17 0 ▼ ▼ ▼ ▼ mask = 0000 1111 1111 1110 0000 0000 0000 0000 ),我们可以设置 - | 所有从1m的位。其他位将保持不变。

记住或者像:

n

其中x | 1 = 1 , and x | 0 = x 值可以是x1

通过这样做:

0

我们可以将 num32bit = num32bit | mask; 设置为nm,其余位将保持不变。一个例子, 假设1 = num32bit

然后:

0011 1001 1000 0000 0111 1001 0010 1101

如何制作面膜?

制作掩码,其中0011 1001 1000 0000 0111 1001 0010 1101 <--- num32bit 0000 1111 1111 1110 0000 0000 0000 0000 <--- mask ---------------------------------------- ---------------Bitwise OR operation 0011 1111 1111 1110 0111 1001 0010 1101 <--- new number ---- ▲ ▲ ------------------- |-----------| this bits are from `num32bit` all bits are 1 here "This is what I means by": num32bit = num32bit | mask; 1n的所有位均为m,其他位为0。 我们需要三个步骤:

  1. Create mask_n n=27右侧的所有位都是一个

     BIT NUMBER     31  n=27                              0
                    ▼    ▼                                ▼
     mask_27=       0000 1111 1111 1111 1111 1111 1111 1111
    

    在编程中,这可以通过右移&gt;&gt;创建。 4次。

    并且, 4如何来?

     4 = 32 - n - 1  ==> 31 - 27 ==> 4
    

    另请注意,在~的补充(0)形式中,所有位都是1。 我们在C.中需要unsigned right shift 链接以了解signed and unsigned right shift

  2. 之间的差异
  3. Create mask_m m=17左侧的所有位均为1。

     BIT NUMBER    31              m=17                  0
                   ▼                ▼                    ▼
     mask_17       1111 1111 1111 1110 0000 0000 0000 0000
    
  4. Create mask :上述按位AND:mask = mask_n & mask_m

     mask =         0000 1111 1111 1110 0000 0000 0000 0000
                         ▲           ▲
     BIT NUMBER          27          17
    
  5. 并且,下面是我的getMask(n, m)函数,它返回一个在步骤3中看起来像掩码的无符号数。

    #define BYTE 8
    typedef char byte; // Bit_sizeof(char) == BYTE
    unsigned getMask(unsigned n,
                  unsigned m){
        byte noOfBits = sizeof(unsigned) * BYTE;
        unsigned mask_n = ((unsigned)~0u) >> (noOfBits - n - 1),
                 mask_m = (~0u) << (noOfBits - m),
                 mask = mask_n & mask_m; // bitwise & of 2 sub masks
        return mask;
    }
    

    为了测试我的getMask(),我还编写了使用binary()函数的main()代码,binary()函数以二进制格式打印给定的数字。

    void binary(unsigned);
    int main(){
        unsigned num32bit = 964720941u;
        unsigned mask = 0u;
        unsigned rsult32bit;
        int i = 51;     
        mask = getMask(27, 17);
        rsult32bit  = num32bit | mask;  //set n to m bits 1
        printf("\nSize of int is = %ld bits, and " 
               "Size of unsigned = %ld e.g.\n", sizeof(int) * BYTE,
                                                sizeof(unsigned) * BYTE);
        printf("dec= %-4u, bin= ", 21);
        binary(21);
        printf("\n\n%s %d\n\t   ", "num32bit =", num32bit); 
        binary(num32bit);
        printf("mask\t   "); 
        binary(mask);
        while(i--) printf("-");
        printf("\n\t   "); 
        binary(rsult32bit);
        printf("\n");
        return EXIT_SUCCESS;
    }
    void binary(unsigned dec){
      int i = 0,
          left = sizeof(unsigned) * BYTE - 1;
      for(i = 0; left >= 0; left--, i++){
        printf("%d", !!(dec & ( 1 << left )));
        if(!((i + 1) % 4)) printf(" ");
      }
      printf("\n");
    }  
    

    此测试代码运行方式(输出与我在上面的示例中解释的完全相同):

    Output of code: 
    -----------------
    $ gcc b.c 
    :~$ ./a.out 
    
    Size of int is = 32 bits, and Size of unsigned = 32 e.g.
    dec= 21  , bin= 0000 0000 0000 0000 0000 0000 0001 0101 
    
    num32bit = 964720941
               0011 1001 1000 0000 0111 1001 0010 1101 
    mask       0000 1111 1111 1110 0000 0000 0000 0000 
    ---------------------------------------------------
               0011 1111 1111 1110 0111 1001 0010 1101 
    :~$ 
    

    另外,您可以在两个语句中以较短的形式编写getMask()函数,如下所示:

    unsigned getMask(unsigned n,
                     unsigned m){
        byte noOfBits = sizeof(unsigned) * BYTE;
        return ((unsigned)~0u >> (noOfBits - n - 1)) &
               (~0u << (noOfBits -m));
    }           
    

    注意:我删除了多余的括号,以清理代码。虽然您永远不需要记住运算符的优先级,因为您可以使用()覆盖优先级。但是一个优秀的程序员总是会使用优先级表来编写简洁的代码。

    更好的方法可能是编写如下的Macro():

    #define BYTE 8
    #define _NO_OF_BITS sizeof(unsigned) * BYTE
    #define MASK(n, m)  (((unsigned)~0u >> (_NO_OF_BITS - n - 1)) & \
                        (~0u << (_NO_OF_BITS - m)))
    

    并致电:

    rsult32bit  = num32bit | MASK(27, 17);
    

    将所有零位从n设置为m


    要将所有位从n设置为m = 0,并且复位不变,您只需要~的补码(mask)。

    mask      0000 1111 1111 1111 1000 0000 0000 0000 
    ~mask      1111 0000 0000 0000 0111 1111 1111 1111   <-- complement 
    

    还需要|运算符来设置零&

    记住 AND 的工作原理如下:

    x & 0 = 0   , and 
    x & 0 = 0 
    

    其中x值可以是1或0。

    因为我们已经有一个按位补码~运算符和&运算符。我们只需要这样做 [解决方案]

    rsult32bit  = num32bit & ~MASK(27, 17);
    

    它的工作原理如下:

    num32bit = 964720941
           0011 1001 1000 0000 0111 1001 0010 1101 
    mask   1111 0000 0000 0000 0111 1111 1111 1111 
    ---------------------------------------------------
           0011 0000 0000 0000 0111 1001 0010 1101