有人可以解释一下这个 bitMask 代码是如何工作的吗?
Can someone explain how this bitMask code works?
这是我的搭档想出的代码,但出于某种原因,我无法联系到他,问他应该如何工作。我已经经历过很多次了,但似乎无法得到我应该得到的答案。
/**
* 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);
}
在你的例子中,根据你的函数中的描述,函数正在做你似乎打算做的事情。主要问题是您使用的是 int
而不是 unsigned int
。这将导致符号扩展出现问题。 (更不用说 C 语言中缺少对带符号移位的定义)。
到 unsigned
的简单转换将向您展示它正在按预期运行:
简短示例:
#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;
}
输出
$ ./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
这个函数实际上是不正确的:对于较大的 highbit
和 lowbit
值,它可能具有特定于实现的行为甚至是未定义的行为。它应该使用 return unsigned
类型:
unsigned bitMask(int highbit, int lowbit) {
unsigned i = ~0U;
return ~(i << highbit << 1) & (i << lowbit);
}
步骤如下:
i = ~0U;
将 i 设置为所有位 1.
i << highbit
将这些位左移,在低位插入 highbit
0 位。
i << highbit << 1
为多一个 0 位腾出空间。不应将此表达式简化为 i << (highbit + 1)
,因为如果 highbit + 1
变得大于或等于 i
.
类型中的位数,则此类移位是实现定义的
~(i << highbit << 1)
补充此掩码,创建一个掩码,其中 highbit + 1
位设置在低位位置,0 位设置为高位。
i << lowbit
创建一个掩码 lowbit
0 位,高位 1。
~(i << highbit << 1) & (i << lowbit)
计算这 2 个掩码的交集,结果有 1 位从位号 lowbit
到位号 highbit
包括在内,从 0
表示最不重要。
示例:
bitMask(31, 0)
-> 0xFFFFFFFF
.
bitMask(0, 0)
-> 0x00000001
.
bitMask(31, 16)
-> 0xFFFF0000
.
bitMask(15, 0)
-> 0x0000FFFF
.
这种编号方式用于硬件规格。我个人更喜欢一种不同的方法,其中指定要跳过的位数和要设置的位数,更符合位域规范:
unsigned bitSpec(int start, int len) {
return (~0U >> (32 - len)) << start;
}
和相同的例子:
bitSpec(0, 32)
-> 0xFFFFFFFF
.
bitSpec(0, 1)
-> 0x00000001
.
bitSpec(16, 16)
-> 0xFFFF0000
.
bitSpec(0, 16)
-> 0x0000FFFF
.
这是我的搭档想出的代码,但出于某种原因,我无法联系到他,问他应该如何工作。我已经经历过很多次了,但似乎无法得到我应该得到的答案。
/**
* 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);
}
在你的例子中,根据你的函数中的描述,函数正在做你似乎打算做的事情。主要问题是您使用的是 int
而不是 unsigned int
。这将导致符号扩展出现问题。 (更不用说 C 语言中缺少对带符号移位的定义)。
到 unsigned
的简单转换将向您展示它正在按预期运行:
简短示例:
#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;
}
输出
$ ./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
这个函数实际上是不正确的:对于较大的 highbit
和 lowbit
值,它可能具有特定于实现的行为甚至是未定义的行为。它应该使用 return unsigned
类型:
unsigned bitMask(int highbit, int lowbit) {
unsigned i = ~0U;
return ~(i << highbit << 1) & (i << lowbit);
}
步骤如下:
i = ~0U;
将 i 设置为所有位 1.i << highbit
将这些位左移,在低位插入highbit
0 位。
类型中的位数,则此类移位是实现定义的i << highbit << 1
为多一个 0 位腾出空间。不应将此表达式简化为i << (highbit + 1)
,因为如果highbit + 1
变得大于或等于i
.~(i << highbit << 1)
补充此掩码,创建一个掩码,其中highbit + 1
位设置在低位位置,0 位设置为高位。i << lowbit
创建一个掩码lowbit
0 位,高位 1。~(i << highbit << 1) & (i << lowbit)
计算这 2 个掩码的交集,结果有 1 位从位号lowbit
到位号highbit
包括在内,从0
表示最不重要。
示例:
bitMask(31, 0)
->0xFFFFFFFF
.bitMask(0, 0)
->0x00000001
.bitMask(31, 16)
->0xFFFF0000
.bitMask(15, 0)
->0x0000FFFF
.
这种编号方式用于硬件规格。我个人更喜欢一种不同的方法,其中指定要跳过的位数和要设置的位数,更符合位域规范:
unsigned bitSpec(int start, int len) {
return (~0U >> (32 - len)) << start;
}
和相同的例子:
bitSpec(0, 32)
->0xFFFFFFFF
.bitSpec(0, 1)
->0x00000001
.bitSpec(16, 16)
->0xFFFF0000
.bitSpec(0, 16)
->0x0000FFFF
.