0

我有一个32-bit数字并且不使用 for 循环,我想将m位设置 n位。

例如:

m位可能是2ndor5th9thor 10th
n位可能是 22nd2711th

我假设(m < n)。

请帮助我。谢谢

4

1 回答 1

12

假设位从 LSB 到 MSB 编号:

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

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

在上图中,我展示了位是如何从 LSB 到 MSB 编号的。n注意和mwhere的相对位置n > m


将(全一)位从 n 设置为 m


在 32 位数字中设置1从位置mn(where ) 的所有位。n > m您需要一个 32 位掩码,其中所有位为1from nm其余位为0.

例如,要设置从m=17到的所有位,n=27我们需要像这样的掩码:

BIT NUMBER    31   n=27        m=17                  0
               ▼    ▼           ▼                    ▼
mask =         0000 1111 1111 1110 0000 0000 0000 0000

如果我们有任何 32 位数字,通过按位 OR ( |) 与该数字,我们可以将1所有位设置为从mn。所有其他位将保持不变。

记住OR 的工作方式如下:

x | 1 = 1   , and 
x | 0 = x 

其中 xvalue 可以是10

所以通过这样做:

 num32bit = num32bit | mask; 

我们可以设置nm1,其余位将保持不变。例如,假设,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

这就是我的意思:

     num32bit = num32bit | mask; 

##如何制作面具?

要制作一个所有位都是1fromnm其他位是 的掩码0,我们需要三个步骤:

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

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

    在编程中,这可以通过右移 ( >>) 4 次来创建。

    而且,为什么4

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

    另请 注意:~0

  2. Create mask_m:左侧的所有位m=17都是一。

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

     mask =         0000 1111 1111 1110 0000 0000 0000 0000
                         ▲           ▲
     BIT NUMBER          27          17
    

而且,下面是我的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()还写了一个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));
}           

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

更好的方法可能是编写如下宏:

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

并调用:

result32bit  = 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 
于 2013-04-10T06:06:16.870 回答