关于编码风格:C中的按位索引?

关于编码风格:C中的按位索引?

bitwise indexing in C?

我正在尝试实现一个已有的数据压缩想法,并且由于我想将其运行在大量测试数据上,因此我曾想过用C编写代码(我主要在Ruby和 Tcl。)

浏览关于C的O'Reilly'cow'书籍,我意识到我不能简单地索引简单的'char'或'int'类型变量的位,因为我想进行按位比较和运算符。

我的看法正确吗? 对我来说,使用枚举类型来表示位是否合理(并制作一个这些类型的数组,并编写要与char相互转换的函数)? 如果是这样,在标准库中定义的这种类型和功能是否已经存在? 还有其他(更好的)方法吗? 有人可以指出我的地方是否有示例代码?

谢谢 -


按照Kyle所说的,您可以使用宏为您完成艰苦的工作。

It is possible.

To set the nth bit, use OR:

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

To clear a bit, use AND:

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

To flip a bit, use XOR:

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

要么...

1
2
3
#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))

然后,您可以在类似以下代码的代码中使用它:

1
2
3
4
5
6
int myVar = 0;
SetBit(myVar, 5);
if (GetBit(myVar, 5))
{
  // Do something
}

有可能的。

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

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

要清除一点,请使用AND:

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

要翻转一点,请使用XOR:

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

要获取一点点的值,请使用shift和AND:

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

注意:右移5是为了确保该值是0或1。如果您只对0 /不是0感兴趣,则无需进行移位即可。


看看这个问题的答案。


理论

没有C语言语法可用于访问或设置内置数据类型的第n位(例如" char")。但是,您可以使用逻辑"与"操作访问位,并使用逻辑"或"操作设置位。

举例来说,假设您有一个包含1101的变量,并且想要从左开始检查第二位。只需使用0100进行逻辑与:

1
2
3
4
1101
0100
---- AND
0100

如果结果不为零,则必须设置第二位;否则,设置为0。否则未设置。

如果要从左开始设置第3位,则对0010执行逻辑或:

1
2
3
4
1101
0010
---- OR
1111

您可以使用C运算符&&(对于AND)和|| (对于OR)执行这些任务。您将需要自己构造位访问模式(在上面的示例中为0100和0010)。诀窍是要记住,最低有效位(LSB)的计数为1s,下一个LSB??的计数为2s,然后为4s,依此类推。因此,第n个LSB(从0开始)的位访问模式仅为2 ^的值。 。在C中计算此值的最简单方法是将二进制值0001(在此四位示例中)向左移动所需的位数。由于此值在无符号整数样量中始终等于1,因此它只是'1 << n'

1
2
3
4
5
6
7
8
9
10
11
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!
"
);} /* Perform the test. */

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

此示例尚未经过测试,但应用于说明总体思路。


各个位的索引如下。

定义这样的结构:

1
2
3
4
5
6
7
8
struct
{
  unsigned bit0     : 1;
  unsigned bit1     : 1;
  unsigned bit2     : 1;
  unsigned bit3     : 1;
  unsigned reserved : 28;
} bitPattern;

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

1
CopyMemory( &input, &value, sizeof(value) );

要查看第2位是高还是低:

1
int state = bitPattern.bit2;

希望这可以帮助。


要查询具有特定索引的位状态:

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

设置位:

1
varabile |= 1 << bit_index;

重新启动位:

1
variable &= ~( 1 << bit_index );


尝试使用位域。请注意,编译器的实现可能会有所不同。

http://publications.gbdirect.co.uk/c_book/chapter6/bitfields.html


有一个用于位的标准库容器:std :: vector。它在图书馆中专门用于节省空间。还有一个boost dynamic_bitset类。

这些使您可以对一组布尔值执行操作,基础存储的每个值使用一位。

提升动态位集文档

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

当然,您也可以手动处理其他整数类型的各个位。如果这样做,则应使用无符号类型,以便在决定对设置了高位的值进行右移时不会出现未定义的行为。但是,听起来您想要容器。

对于声称这会比所需空间多32倍的评论者:boost :: dynamic_bitset和vector专门用于每个条目使用一位,因此,假设您实际上想要的位数超过了位数,则不会有空间损失。基本类型。这些类使您可以通过有效的基础存储来处理大型容器中的各个位。如果您只想(说)32位,请使用int。如果需要大量的位,则可以使用库容器。


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

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

获取一个字符的最高位。您甚至可以忽略右移并在0上进行测试。

1
bit = char & 0xF0;

如果该位置1,则结果将> 0;

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

1
2
3
4
#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

等等...

这给您:

1
bit = char & BIT_1;

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

设置一下:

1
char |= BIT_2;

要清除一点:

1
char &= ~BIT_3

切换一下

1
char ^= BIT_4

这有帮助吗?


推荐阅读