解释用于设置,清除和测试单个位的算法

时间:2008-11-06 07:10:20

标签: c bit-manipulation

嘿,在Programming Pearls一书中,有一个源代码,用于设置,清除和测试一个实际上是一组表示的整数数组中给定索引的位。

代码如下:

#include<stdio.h>
#define BITSPERWORD 32
#define SHIFT 5
#define MASK 0x1F
#define N 10000000

int a[1+ N/BITSPERWORD];

void set(int i)
{
    a[i>>SHIFT] |= (1<<(i & MASK));
}

void clr(int i)
{
    a[i>>SHIFT] &= ~(1<<(i & MASK));
}

int test(int i)
{
    a[i>>SHIFT] & (1<<(i & MASK));
}

有人能解释一下SHIFT和MASK定义的原因吗?他们在代码中的目的是什么?

我已经阅读了之前的相关question

5 个答案:

答案 0 :(得分:7)

VonC总体上发布了一个关于位掩码的好答案。以下是一些针对您发布的代码更具体的信息。

给定一个表示位的整数,我们计算出该位的哪个成员保存该位。即:{0}位住在a[0],位32到63位于a[1],等等。i>>SHIFT所做的全部是i / 32。这解决了a中的哪个成员的位置。使用优化编译器,这些可能是等效的。

显然,现在我们已经找到了位于a的那个位成员,我们需要确保在该整数中设置正确的位。这就是1 << i的作用。但是,我们需要确保不会尝试访问32位整数中的第33位,因此使用1 << (i & 0x1F)限制了移位操作。这里的神奇之处在于0x1F为31,所以我们永远不会将i所代表的位移到31位以上(否则它应该在a的下一个成员中移位)。

答案 1 :(得分:6)

Here(获得此主题的一般答案)

位掩码是一个值(可以存储在变量中),使您能够在整数类型中隔离一组特定的位。

通常,屏蔽将您感兴趣的位设置为1,所有其他位设置为0.然后屏蔽允许您隔离位的值,清除所有位或设置所有位或设置比特的新值。

屏蔽(特别是多位的)通常具有相关的移位值,即位需要向左移位的量,以便将最低有效屏蔽位移位到该类型中的最低有效位。

例如,使用16位短数据类型假设您希望能够屏蔽位3,4和5(LSB为数字0)。你掩饰和转移看起来像

#define MASK 0x0038
#define SHIFT 3

掩码通常以十六进制分配,因为使用该基数中的数据类型中的位更容易处理,而不是十进制。历史上,八进制也用于位掩码。

如果我有一个变量var,其中包含与掩码相关的数据,那么我可以将这些位隔离开来

var & MASK

我可以像这样隔离所有其他位

var & ~MASK

我可以清除像这样的位

var &= ~MASK;

我可以像这样清除所有其他位

var &= MASK;

我可以像这样设置所有位

var |= MASK;

我可以像这样设置所有其他位

var |= ~MASK;

我可以像这样提取位的十进制值

(var & MASK) >> SHIFT

我可以为这样的位分配一个新值

var &= ~MASK;
var |= (newValue << SHIFT) & MASK;

答案 2 :(得分:5)

当你想在数组中设置一个位时,你必须

  1. 寻找正确的数组索引和
  2. 在此数组项中设置相应的位。
  3. 一个数组项中有BITSPERWORD(= 32)位,这意味着索引i必须分为两部分:

    • 最右边的5位用作数组项中的索引和
    • 其余位(最左边28位)用作数组的索引。

    你得到:

    • 最左边的28位,丢弃最右边的五个,这正是 i>>SHIFT 所做的,
    • 最右边的五位通过屏蔽除了最右边的五位之外的任何内容,这是 i & MASK 的作用。

    我想你了解其余部分。

答案 3 :(得分:0)

Bitwise operation以及Mask的主要段落是一个简明的解释,并包含一些进一步研究的指示。

将8位字节视为来自8个成员的Universe中的一组元素。当设置相应位时,成员 IN 该组。稍微设置一次不会修改set membership(一个位只能有2个状态)。 C 中的bitwise operators通过屏蔽转移提供对位的访问。

答案 4 :(得分:0)

代码试图通过数组存储N位,其中数组的每个元素都包含BITSPERWORD(32)位。

因此,如果您尝试访问位i,则需要计算存储它的数组元素的索引(i/32),这是i>>SHIFT所做的。

然后你需要访问我们刚才得到的数组元素中的那个位。

(i & MASK)给出数组元素(word)的位位置。 (1<<(i & MASK))使该位置的位置设置。

现在,您可以a[i>>SHIFT](1<<i & MASK))中设置/清除/测试该位。

您可能还认为i是32位数,第6~31位是数组元素存储的索引,第0~5位表示字中的位位置。