8

我正在尝试实现我曾经拥有的数据压缩想法,并且由于我正在想象针对大量测试数据运行它,因此我曾考虑用 C 对其进行编码(我主要有 Ruby 和Tcl。)

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

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

谢谢 -

4

9 回答 9

10

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

有可能的。

要设置第 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
}
于 2008-09-15T13:49:49.550 回答
7

有可能的。

要设置第 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

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

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

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

于 2008-09-15T13:13:24.007 回答
3

看看这个问题的答案。

于 2008-09-15T13:19:22.963 回答
2

理论

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

例如,假设您有一个包含 1101 的变量,并且您想检查左侧的第二位。只需对 0100 执行逻辑与:

1101
0100
---- AND
0100

如果结果非零,则第 2 位必须已设置;否则未设置。

如果要设置左起第 3 位,则与 0010 执行逻辑或:

1101
0010
---- OR
1111

您可以使用 C 运算符 &&(用于 AND)和 || (对于 OR)来执行这些任务。您将需要自己构建位访问模式(上述示例中的 0100 和 0010)。诀窍是记住最低有效位 (LSB) 计为 1,下一个 LSB 计为 2,然后是 4,依此类推。因此,第 n 个 LSB(从 0 开始)的位访问模式就是 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);

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

于 2008-09-15T13:48:54.373 回答
1

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

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

设置位:

varabile |= 1 << bit_index;

要重新启动位:

variable &= ~( 1 << bit_index );
于 2008-09-15T13:19:28.673 回答
0

如果你想索引一点,你可以:

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

获取一个字符的 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

ETC...

这给了你:

bit = char & BIT_1;

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

设置一点:

char |= BIT_2;

要清除一点:

char &= ~BIT_3

稍微切换一下

char ^= BIT_4

这个帮助?

于 2008-09-15T13:15:57.743 回答
0

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

这些将允许您对一组布尔值执行操作,每个底层存储值使用一个位。

Boost 动态位集文档

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

当然,您也可以手动寻址其他整数类型中的各个位。如果你这样做,你应该使用无符号类型,这样如果决定对设置了高位的值进行右移,你就不会得到未定义的行为。但是,听起来您想要容器。

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

于 2008-09-15T13:25:45.770 回答
0

尝试使用位域。请注意,实现可能因编译器而异。

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

于 2008-09-15T13:27:22.180 回答
0

可以如下索引各个位。

定义一个像这样的结构:

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

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

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

要查看位 2 是高还是低:

int state = bitPattern.bit2;

希望这可以帮助。

于 2008-09-15T13:55:21.533 回答