C中的大位数组

时间:2010-09-24 18:44:14

标签: c linux bitarray

我们的操作系统教授提到,为了为新进程分配进程ID,内核会逐步搜索大小相当于最大进程数(默认为~32,768)的数组中的第一个零位,其中一个已分配的进程id中有1个存储在其中。

据我所知,C中没有位数据类型。显然,我在这里缺少一些东西。

是否有任何这样的特殊构造可以构建一个位数组?这完全是怎么做的?

更重要的是,在这样的阵列上可以执行哪些操作?

4 个答案:

答案 0 :(得分:4)

位数组只是字节数组,您可以使用bitwise operators来读取各个位。

假设您有一个1字节的char变量。这包含8位。您可以通过执行值为1的按位AND运算来测试最低位是否为真,例如

 char a = /*something*/;
 if (a & 1) {
    /* lowest bit is true */
 }

请注意,这是&符号。它与逻辑 AND运算符&&完全不同。这是有效的,因为a & 1将“掩盖”除第一个之外的所有位,因此a & 1当且仅当a的最低位为1时才为非零。同样,您可以检查如果第二个最低位为真,则将其与2进行“与”运算,第三个与“和”运算符为4,等等,以获得2的持续幂。

因此,32,768个元素的位数组将表示为4096个元素的字节数组,其中第一个字节保存位0-7,第二个字节保存位8-15,等等。执行检查时,代码将从包含要检查的位的数组中选择字节,然后使用按位运算从字节中读取位值。

就操作的内容而言,与任何其他数据类型一样,您可以读取值和写入值。我解释了如何读取上面的值,我将解释如何在下面写入值,但如果你真的对理解按位操作感兴趣,请阅读我在第一句中提供的链接。

如何写入取决于是否要写入0或1.要将1位写入字节a,执行与AND操作相反的操作:OR操作,例如

 char a = /*something*/;
 a = a | 1; /* or a |= 1 */

此后,无论之前是否设置,a的最低位都将设置为1。再次,您可以将此写入第二个位置,方法是将1替换为2,或者将第三个位置替换为4,依此类推2的幂。

最后,要写入一个零位,您要与要写入的位置的反向进行AND,例如

 char a = /*something*/;
 a = a & ~1; /* or a &= ~1 */

现在,a的最低位设置为0,无论其先前的值如何。这是有效的,因为~1之外的所有位设置为最低设置为1,最低设置为零。这会将最低位“屏蔽”为零,并将a的其余位单独保留。

答案 1 :(得分:3)

struct可以为成员分配位大小,但这是“C”中“位类型”的范围。

struct int_sized_struct {
   int foo:4;
   int bar:4;
   int baz:24;
};

其余部分是通过按位操作完成的。例如。搜索PID位图可以通过以下方式完成:

extern uint32_t *process_bitmap;
uint32_t *p = process_bitmap;
uint32_t bit_offset = 0;
uint32_t bit_test;

/* Scan pid bitmap 32 entries per cycle. */
while ((*p & 0xffffffff) == 0xffffffff) {
  p++;
}

/* Scan the 32-bit int block that has an open slot for the open PID */
bit_test = 0x80000000;
while ((*p & bit_test) == bit_test) {
   bit_test >>= 1;
   bit_offset++;
}
pid = (p - process_bitmap)*8 + bit_offset;

这比使用每个PID一个字节的简单for循环扫描一样快大约32倍。 (实际上,大于32倍,因为更多的位图将保留在CPU缓存中。)

答案 2 :(得分:1)

答案 3 :(得分:0)

C中没有位类型,但位操作相当简单。一些处理器具有特定于位的指令,下面的代码可以很好地优化,即使没有它应该非常快。使用32位字而不是字节数组可能会更快或更快。内联而不是函数也有助于提高性能。

如果你有内存要刻录,只需使用整个字节来存储一位(或整个32位数字等),这会大大提高性能,但代价是使用的内存。


unsigned char data[SIZE];

unsigned char get_bit ( unsigned int offset )
{
    //TODO: limit check offset
    if(data[offset>>3]&(1<<(offset&7))) return(1);
    else return(0);
}
void set_bit ( unsigned int offset, unsigned char bit )
{
    //TODO: limit check offset
    if(bit) data[offset>>3]|=1<<(offset&7);
    else    data[offset>>3]&=~(1<<(offset&7));
}