我需要在内存缓冲区中的指定位偏移处读取和写入指定位长度(不一定是8的倍数)的数值,这是最重要的位。
例如,在偏移量6和位长度4处写入值5:
before: 11111111 11111111
bits: ^^ ^^
after: 11111101 01111111
所以我正在寻找的功能可以这样定义:
unsigned get_bits (unsigned char *buffer, int offset, int bit_size);
void set_bits (unsigned char *buffer, int offset, int bit_size,
unsigned value);
示例用法:
set_bits (buffer, 6, 4, 5);
unsigned v = get_bits (buffer, 6, 4);
assert (v == 5);
这些函数将用于在相对较大的缓冲区中读取/写入少量值(过滤高容量的网络流量),因此我使用std::bitset
丢弃(可能是错误的)。
是否有可用于实现/简化此任务的现有库?关于实施它的任何建议?
答案 0 :(得分:2)
比特摆弄很少容易。这是一个完整的工作示例,说明如何做你想做的事。
这里的一个大问题是跨字节边界读取和写入数字块。如果你将它们分成一口大小的块,问题总是更容易,如果你原谅双关语。
首先,我创建了一个类似std :: bitset的类,它可以包装用户定义的缓冲区。它让我们在二进制数据的大缓冲区中摆弄各个位。
#include <cassert> // for assert
#include <cstring> // for memset
// A wrapper for a data buffer providing bit-level access.
class BitBuffer {
public:
BitBuffer (unsigned char *src_buffer, size_t byte_size)
: m_data( src_buffer ), m_size( byte_size )
{
if (m_size) assert(m_data);
}
// Clear the buffer (set all bits to 0).
void clear () {
memset( m_data, 0, m_size );
}
// Get an individual bit's value.
bool get (size_t bitpos) const {
assert( bitpos / 8 < m_size );
return m_data[ bitpos / 8 ] & ( 1 << ( bitpos % 8 ) );
}
// Set an individual bit's value.
void set (size_t bitpos, bool val=true) {
assert( bitpos / 8 < m_size );
if( val ) {
m_data[ bitpos / 8 ] |= ( 1 << ( bitpos % 8 ) );
} else {
m_data[ bitpos / 8 ] &= ~( 1 << ( bitpos % 8 ) );
}
}
// Switch off a bit.
void reset (size_t bitpos) {
set( bitpos, false );
}
// Flip a bit.
void flip (size_t bitpos) {
set( bitpos, ! get( bitpos ) );
}
// Return the size of the buffer in bytes.
size_t byte_size () const { return m_size; }
// Return the size of the buffer in bits.
size_t bit_size () const { return m_size * 8; }
// Return a const pointer to the buffer.
unsigned char const * buffer () const { return m_data; }
private:
unsigned char * m_data;
size_t m_size;
};
然后我编写了一些函数来从缓冲区中获取和设置位块,首先是MSB。
unsigned get_bits (BitBuffer& buffer, size_t offset, size_t bit_size)
{
unsigned bits = 0;
for (size_t i = 0; i < bit_size; i++) {
// We reverse the order of the bits, so the first bit read
// from the buffer maps to the high bit in 'bits'.
bits |= ( buffer.get( offset + i ) << (bit_size - 1 - i) );
}
return bits;
}
void set_bits (BitBuffer& buffer, size_t offset, size_t bit_size, unsigned bits)
{
for (size_t i = 0; i < bit_size; i++) {
// We reverse the order of the bits, so the high bit of 'bits'
// gets written to the buffer first.
bool bit_value = bits & ( 1 << (bit_size - 1 - i) );
buffer.set( offset + i, bit_value );
}
}
测试工具:
#include <cstdio>
// Print the bits of the buffer to stdout.
void dump_buffer (BitBuffer& buffer)
{
for (size_t i = 0; i < buffer.bit_size(); i++) {
printf( "%i", buffer.get(i) );
}
printf("\n");
}
int main()
{
const size_t byte_size = 4; // size of buffer in bytes
unsigned char * raw_buffer = new unsigned char[ byte_size ];
BitBuffer buffer( raw_buffer, byte_size );
buffer.clear();
printf("Test #0: contents of 4-byte buffer:\n");
// Show the buffer.
dump_buffer( buffer );
printf("\nTest #1: setting and flipping bits:\n");
// Set some bits
buffer.set( 5 );
buffer.set( 10 );
buffer.set( 12 );
buffer.set( 31 );
// Show the buffer.
dump_buffer( buffer );
// Read some bits.
printf( "Value at 12 before flip: %i\n", buffer.get( 12 ) );
buffer.flip( 12 );
printf( "Value at 12 after flip: %i\n", buffer.get( 12 ) );
printf("\nTest #2: setting all 1's, and writing 5, length 4 to offset 6:\n");
// Fill with 1's.
set_bits(buffer, 0, 32, 0xFFFFFFFF);
// Set 5 at offset 6, bit size 4.
set_bits(buffer, 6, 4, 5);
assert( get_bits(buffer, 6, 4) == 5 );
// Show the buffer.
dump_buffer( buffer );
// All done.
delete raw_buffer;
return 0;
}
要编译,只需将所有这些转储到一个文件中并进行编译即可。测试运行输出:
Test #0: contents of 4-byte buffer:
00000000000000000000000000000000
Test #1: setting and flipping bits:
00000100001010000000000000000001
Value at 12 before flip: 1
Value at 12 after flip: 0
Test #2: setting all 1's, and writing 5, length 4 to offset 6:
11111101011111111111111111111111
如果您发现它有用,或者您遇到任何问题,请告诉我。
答案 1 :(得分:1)
要将特定位设置为1,您可以创建一系列全部为0的位,除了您要设置的位(那些是1)和OR
它与现有位。要将特定位设置为0,除了你想要的0之外,你只做所有位都是1,你使用AND
运算符。
示例:
before: 11111111 11111111
bits to SET: _^ _^ 5 is 0101, so we SET just the 1 bits, _ is placeholder
bitmask: OR 00000001 01000000
result: 11111111 11111111 No different because they were all 1s already.
bits to RESET: ^_ ^_ RESET the 0s
bitmask: AND 11111101 01111111
result: 11111101 01111111
不知道有任何图书馆可以帮助解决这个问题。