有人能解释一下这个位掩码是如何工作的吗?

时间:2021-03-03 08:19:15

This is code that my partner came up with but for some reason I can't get a hold of him to ask him how it's suppose to work. I've been through it many times now and can't seem to get the answer I'm suppose to get.

这是我的搭档提出的代码,但由于某种原因,我无法让他问他该如何工作。我已经经历过很多次了,似乎无法得到我想要的答案。

/**
 * bitMask - Generate a mask consisting of all 1's 
 *   lowbit and highbit
 *   Examples: bitMask(5,3) = 0x38
 *   Assume 0 <= lowbit <= 31, and 0 <= highbit <= 31
 *   If lowbit > highbit, then mask should be all 0's
 *   Legal ops: ! ~ & ^ | + << >>
 */
int bitMask(int highbit, int lowbit) {
   int i = ~0;
   return ~(i << highbit << 1) & (i << lowbit);
}

2 个解决方案

#1


3  

This function is actually incorrect: for large values of highbit and lowbit, it may have implementation specific behavior or even undefined behavior. It should use and return unsigned types:

这个函数实际上是不正确的:对于高比特和低比特的大值,它可能具有实现特定的行为,甚至是未定义的行为。它应该使用和返回无符号类型:

unsigned bitMask(int highbit, int lowbit) {
    unsigned i = ~0U;
    return ~(i << highbit << 1) & (i << lowbit);
}

Here are the steps:

下面是步骤:

  • i = ~0U; sets i to all bits 1.

    我= ~ 0 u;将i设为所有位1。

  • i << highbit shifts these bits to the left, inserting highbit 0 bits in the low order bits.

    i << highbit将这些位向左移动,在低阶位中插入高位0位。

  • i << highbit << 1 makes room for one more 0 bit. One should not simplify this expression as i << (highbit + 1) because such a bit shift is implementation defined if highbit + 1 becomes larger or equal to the number of bits in the type of i.

    i << highbit << 1为多一个0位腾出空间。我们不应该将这个表达式简化为i < (highbit + 1),因为如果highbit + 1变得更大或等于i类型的比特数,那么就定义了这种位移。

  • ~(i << highbit << 1) complements this mask, creating a mask with highbit + 1 bits set in the low order positions and 0 for the higher bits.

    ~(i << highbit << < 1)补充了这个掩码,创建了一个高比特+ 1位的掩码,设置在低阶位置,高比特为0。

  • i << lowbit creates a mask with lowbit 0 bits and 1 in the higher positions.

    i << lowbit创建了一个具有低位0位和1的高位置的掩码。

  • ~(i << highbit << 1) & (i << lowbit) computes the intersection of these 2 masks, result has 1 bits from bit number lowbit to bit number highbit inclusive, numbering the bits from 0 for the least significant.

    ~(i << highbit << 1) & (i << lowbit)计算这两个掩码的交点,结果从位号低位到位号高位包含1位,从0到最不重要的位编号。

examples:

例子:

  • bitMask(31, 0) -> 0xFFFFFFFF.
  • 位掩码(31岁,0)- > 0 xffffffff。
  • bitMask(0, 0) -> 0x00000001.
  • 位掩码(0,0)- > 0 x00000001。
  • bitMask(31, 16) -> 0xFFFF0000.
  • 16位掩码(31日)- > 0 xffff0000。
  • bitMask(15, 0) -> 0x0000FFFF.
  • 位掩码(0)- > 0 x0000ffff。

This numbering method is used in hardware specifications. I personally prefer a different method where one specifies the number of bits to skip and the number of bits to set, more consistent with bit-field specifications:

这种编号方法用于硬件规范。我个人更喜欢另一种方法,其中一种方法指定要跳过的比特数和要设置的比特数,更符合位域规范:

unsigned bitSpec(int start, int len) {
    return (~0U >> (32 - len)) << start;
}

and the same examples:

同样的例子:

  • bitSpec(0, 32) -> 0xFFFFFFFF.
  • bitSpec xffffffff(0,32)- > 0。
  • bitSpec(0, 1) -> 0x00000001.
  • bitSpec x00000001(0,1)- > 0。
  • bitSpec(16, 16) -> 0xFFFF0000.
  • bitSpec xffff0000(16日16)- > 0。
  • bitSpec(0, 16) -> 0x0000FFFF.
  • bitSpec x0000ffff(0,16)- > 0。

#2


0  

In your case, given the description included with your function, the function is doing exactly what you seem to intend it to do. The primary problem is you are using int instead of unsigned int. That will cause problems with sign extension. (not to mention the lack of definition for signed shifts in C).

在您的例子中,考虑到您的函数所包含的描述,函数正在做您似乎想要做的事情。主要的问题是使用int而不是无符号int,这会导致符号扩展的问题。(更不用说C中没有对有符号的移位进行定义了)。

A simple conversion to unsigned will show you it is operating as you expect:

一个简单的转换为unsigned将显示它正在按您的期望运行:

Short example:

短的例子:

#include <stdio.h>
#include <stdlib.h>

unsigned int bitMask (unsigned int highbit, unsigned int lowbit) {
    unsigned int i = ~0;
    return ~(i << highbit << 1) & (i << lowbit);
}

char *binstr (unsigned long n, unsigned char sz, unsigned char szs, char sep) {

    static char s[128 + 1] = {0};
    char *p = s + 128;
    unsigned char i;

    for (i = 0; i < sz; i++) {
        p--;
        if (i > 0 && szs > 0 && i % szs == 0)
            *p-- = sep;
        *p = (n >> i & 1) ? '1' : '0';
    }

    return p;
}

int main (int argc, char **argv) {

    unsigned high = argc > 1 ? (unsigned)strtoul (argv[1], NULL, 10) : 5;
    unsigned low  = argc > 2 ? (unsigned)strtoul (argv[2], NULL, 10) : 3;

    printf ("%s\n", binstr (bitMask (high, low), 32, 8, '-'));

    return 0;
}

Output

输出

$ ./bin/bitmask
00000000-00000000-00000000-00111000

$ ./bin/bitmask 10 3
00000000-00000000-00000111-11111000

$ ./bin/bitmask 31 5
11111111-11111111-11111111-11100000

$ ./bin/bitmask 4 8
00000000-00000000-00000000-00000000

#1


3  

This function is actually incorrect: for large values of highbit and lowbit, it may have implementation specific behavior or even undefined behavior. It should use and return unsigned types:

这个函数实际上是不正确的:对于高比特和低比特的大值,它可能具有实现特定的行为,甚至是未定义的行为。它应该使用和返回无符号类型:

unsigned bitMask(int highbit, int lowbit) {
    unsigned i = ~0U;
    return ~(i << highbit << 1) & (i << lowbit);
}

Here are the steps:

下面是步骤:

  • i = ~0U; sets i to all bits 1.

    我= ~ 0 u;将i设为所有位1。

  • i << highbit shifts these bits to the left, inserting highbit 0 bits in the low order bits.

    i << highbit将这些位向左移动,在低阶位中插入高位0位。

  • i << highbit << 1 makes room for one more 0 bit. One should not simplify this expression as i << (highbit + 1) because such a bit shift is implementation defined if highbit + 1 becomes larger or equal to the number of bits in the type of i.

    i << highbit << 1为多一个0位腾出空间。我们不应该将这个表达式简化为i < (highbit + 1),因为如果highbit + 1变得更大或等于i类型的比特数,那么就定义了这种位移。

  • ~(i << highbit << 1) complements this mask, creating a mask with highbit + 1 bits set in the low order positions and 0 for the higher bits.

    ~(i << highbit << < 1)补充了这个掩码,创建了一个高比特+ 1位的掩码,设置在低阶位置,高比特为0。

  • i << lowbit creates a mask with lowbit 0 bits and 1 in the higher positions.

    i << lowbit创建了一个具有低位0位和1的高位置的掩码。

  • ~(i << highbit << 1) & (i << lowbit) computes the intersection of these 2 masks, result has 1 bits from bit number lowbit to bit number highbit inclusive, numbering the bits from 0 for the least significant.

    ~(i << highbit << 1) & (i << lowbit)计算这两个掩码的交点,结果从位号低位到位号高位包含1位,从0到最不重要的位编号。

examples:

例子:

  • bitMask(31, 0) -> 0xFFFFFFFF.
  • 位掩码(31岁,0)- > 0 xffffffff。
  • bitMask(0, 0) -> 0x00000001.
  • 位掩码(0,0)- > 0 x00000001。
  • bitMask(31, 16) -> 0xFFFF0000.
  • 16位掩码(31日)- > 0 xffff0000。
  • bitMask(15, 0) -> 0x0000FFFF.
  • 位掩码(0)- > 0 x0000ffff。

This numbering method is used in hardware specifications. I personally prefer a different method where one specifies the number of bits to skip and the number of bits to set, more consistent with bit-field specifications:

这种编号方法用于硬件规范。我个人更喜欢另一种方法,其中一种方法指定要跳过的比特数和要设置的比特数,更符合位域规范:

unsigned bitSpec(int start, int len) {
    return (~0U >> (32 - len)) << start;
}

and the same examples:

同样的例子:

  • bitSpec(0, 32) -> 0xFFFFFFFF.
  • bitSpec xffffffff(0,32)- > 0。
  • bitSpec(0, 1) -> 0x00000001.
  • bitSpec x00000001(0,1)- > 0。
  • bitSpec(16, 16) -> 0xFFFF0000.
  • bitSpec xffff0000(16日16)- > 0。
  • bitSpec(0, 16) -> 0x0000FFFF.
  • bitSpec x0000ffff(0,16)- > 0。

#2


0  

In your case, given the description included with your function, the function is doing exactly what you seem to intend it to do. The primary problem is you are using int instead of unsigned int. That will cause problems with sign extension. (not to mention the lack of definition for signed shifts in C).

在您的例子中,考虑到您的函数所包含的描述,函数正在做您似乎想要做的事情。主要的问题是使用int而不是无符号int,这会导致符号扩展的问题。(更不用说C中没有对有符号的移位进行定义了)。

A simple conversion to unsigned will show you it is operating as you expect:

一个简单的转换为unsigned将显示它正在按您的期望运行:

Short example:

短的例子:

#include <stdio.h>
#include <stdlib.h>

unsigned int bitMask (unsigned int highbit, unsigned int lowbit) {
    unsigned int i = ~0;
    return ~(i << highbit << 1) & (i << lowbit);
}

char *binstr (unsigned long n, unsigned char sz, unsigned char szs, char sep) {

    static char s[128 + 1] = {0};
    char *p = s + 128;
    unsigned char i;

    for (i = 0; i < sz; i++) {
        p--;
        if (i > 0 && szs > 0 && i % szs == 0)
            *p-- = sep;
        *p = (n >> i & 1) ? '1' : '0';
    }

    return p;
}

int main (int argc, char **argv) {

    unsigned high = argc > 1 ? (unsigned)strtoul (argv[1], NULL, 10) : 5;
    unsigned low  = argc > 2 ? (unsigned)strtoul (argv[2], NULL, 10) : 3;

    printf ("%s\n", binstr (bitMask (high, low), 32, 8, '-'));

    return 0;
}

Output

输出

$ ./bin/bitmask
00000000-00000000-00000000-00111000

$ ./bin/bitmask 10 3
00000000-00000000-00000111-11111000

$ ./bin/bitmask 31 5
11111111-11111111-11111111-11100000

$ ./bin/bitmask 4 8
00000000-00000000-00000000-00000000