C语言中的位索引?

8
我正在尝试实现一个数据压缩的想法,因为我想对大量测试数据运行它,所以我想用C编写它(我主要有Ruby和Tcl等脚本语言的经验)。
在查看O'Reilly关于C语言的书籍时,我意识到我不能像我想要的那样索引简单的“char”或“int”类型变量的位来进行位比较和操作。
我的感知是正确的吗?我是否可以使用枚举类型表示一位(并创建一个这些的数组,并编写将其转换为char的函数和从char转换回该类型的函数)?如果可以,这种类型和函数是否已经在标准库中定义了?还有其他更好的方法吗?是否有某个示例代码可以指导我?
谢谢。
9个回答

12

继Kyle所说的之后,您可以使用宏来为您完成艰苦的工作。

这是可能的。

要设置第n位,请使用OR:

x |= (1 << 5); // 设置从右数第6位

要清除一位,请使用AND:

x &= ~(1 << 5); // 清除从右数第6位

要翻转一位,请使用XOR:

x ^= (1 << 5); // 翻转从右数第6位

或者...

#define GetBit(var, bit) ((var & (1 << bit)) != 0) // Returns true / false if bit is set
#define SetBit(var, bit) (var |= (1 << bit))
#define FlipBit(var, bit) (var ^= (1 << bit))

然后您可以像这样在代码中使用它:

int myVar = 0;
SetBit(myVar, 5);
if (GetBit(myVar, 5))
{
  // Do something
}

8

这是可能的。

要设置第n位,使用OR:

x |= (1 << 5); // sets the 5th-from right

如果要清除某个位,可以使用 AND:

x &= ~(1 << 5); // clears 5th-from-right

要翻转一个比特,请使用异或(XOR):

x ^= (1 << 5); // flips 5th-from-right

要获取一个位的值,使用移位和按位与操作:

(x & (1 << 5)) >> 5 // gets the value (0 or 1) of the 5th-from-right

注:右移 5 位是为了确保该值为 0 或 1。如果您只关心 0/不为 0,则可以在不进行移位的情况下完成。


3

2

理论

在C语言中,没有直接访问或设置内置数据类型(例如 'char')的第n位的语法。但是,您可以使用逻辑 AND 操作访问位,并使用逻辑 OR 操作设置位。

举个例子,假设您有一个变量保存了1101,您想检查左边第二位。只需使用0100进行逻辑 AND 操作:

1101
0100
---- AND
0100

如果结果不为零,则第二位必定被设置;否则未被设置。
如果您想从左侧设置第三位,则执行与0010的逻辑OR操作:
1101
0010
---- OR
1111

您可以使用C运算符&&(表示AND)和||(表示OR)执行这些任务。您需要自己构造位访问模式(上面示例中的0100和0010)。诀窍在于记住,最低有效位(LSB)计数1,下一个LSB计数2,然后是4等。因此,从0开始的第n个LSB的位访问模式仅为2^n的值。在C中计算这个最简单的方法是将二进制值0001(在这个四位示例中)向左移所需的位数。由于这个值在无符号整数类型的数量中始终等于1,因此只需使用'1 << n'即可。 示例
unsigned char myVal = 0x65; /* in hex; this is 01100101 in binary. */

/* Q: is the 3-rd least significant bit set (again, the LSB is the 0th bit)? */
unsigned char pattern = 1;
pattern <<= 3; /* Shift pattern left by three places.*/

if(myVal && (char)(1<<3)) {printf("Yes!\n");} /* Perform the test. */

/* Set the most significant bit. */
myVal |= (char)(1<<7);

这个例子没有经过测试,但应该可以用来说明一般的思路。


1

查询特定索引位的状态:

int index_state = variable & ( 1 << bit_index );

设置位:

varabile |= 1 << bit_index;

重新启动位:

variable &= ~( 1 << bit_index );

0

如果您想索引一位,您可以:

bit = (char & 0xF0) >> 7;

获取 char 的最高有效位(MSB)。您甚至可以省略右移并对 0 进行测试。

bit = char & 0xF0;

如果位被设置,结果将会大于0;

显然,你需要改变掩码以获取不同的位(注:如果不清楚,0xF是位掩码)。可以定义许多掩码,例如:

#define BIT_0 0x1 // or 1 << 0
#define BIT_1 0x2 // or 1 << 1
#define BIT_2 0x4 // or 1 << 2
#define BIT_3 0x8 // or 1 << 3

这将给你:

bit = char & BIT_1;

您可以在上述代码中使用这些定义来成功地在宏或函数中索引位。

设置位:

char |= BIT_2;

澄清一下:

char &= ~BIT_3

切换一个位

char ^= BIT_4

这有帮助吗?


0

个别位可以按以下方式进行索引。

定义一个这样的结构体:

struct
{
  unsigned bit0     : 1;
  unsigned bit1     : 1;
  unsigned bit2     : 1;
  unsigned bit3     : 1;
  unsigned reserved : 28;
} bitPattern;   

现在,如果我想知道名为"value"的变量的各个位值,请执行以下操作:
CopyMemory( &input, &value, sizeof(value) );

判断第二位是高电平还是低电平:

int state = bitPattern.bit2;

希望这可以帮助到你。

0

有一个标准库容器专门用于位操作:std::vector。在库中进行了特殊优化以提高空间效率。此外,还有一个 Boost dynamic_bitset 类。

这些容器可以让您使用基础存储的每个值的一位来执行布尔值集上的操作。

Boost dynamic bitset documentation

有关 STL 文档,请参阅编译器文档。

当然,您也可以手动访问其他整数类型中的单个位。如果这样做,应使用无符号类型,以便在对带高位设置的值进行右移时不会出现未定义行为。但是,根据您的描述,似乎您需要这些容器。

对于声称这比必要的多占用了32倍空间的评论者:boost::dynamic_bitset和vector专门使用每个条目一个位,因此不存在空间惩罚,假设您实际上需要超过原始类型中的位数。这些类允许您在具有高效底层存储的大容器中寻址单个位。如果您只需要(比如)32位,请使用int。如果您需要大量位数,则可以使用库容器。

这使用了比必要的多32倍的数据。原帖作者说他对数据压缩感兴趣。这听起来像是相反的! - Mark Ingram
不,关于vector<bool>和boost::dynamic_bitset的重点在于它们每个bool使用一位。要存储1024个bool,它们将使用128字节加上类开销。你是如何计算出比必要多32倍的存储空间的? - janm

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接