我们的操作系统教授提到,为了为新进程分配进程ID,内核会逐步搜索大小相当于最大进程数(默认为~32,768)的数组中的第一个零位,其中一个已分配的进程id中有1个存储在其中。
据我所知,C中没有位数据类型。显然,我在这里缺少一些东西。
是否有任何这样的特殊构造可以构建一个位数组?这完全是怎么做的?
更重要的是,在这样的阵列上可以执行哪些操作?
答案 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)); }