2012-06-03 17 views
3

我需要读取和写入指定比特长度的数值在(8不一定倍数)指定的比特偏移量存储在存储器缓冲器中,最显著位第一。读/写在指定的位的值的偏移

例如,在写的5值在偏移6和比特长度为4:

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); 

的功能将被用于读取/在一个比较大的缓冲写的一个小数量的值(F过滤高容量的网络流量),所以我丢弃(可能错误地)使用std::bitset

是否有可能被用来实现/简化这一任务的任何现有的库?有关实施它的任何建议?

+0

对这个需求使用模板似乎对我无用 –

+0

@stefanbachert模板在代码将被使用的地方是合理的,但是你是对的,它们在这里没用,所以我删除了它们。 – wroniasty

回答

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 

让我知道你是否觉得它有用,或者如果你有任何问题。

+0

thx @QuasarDonkey,基于你的回答和我的一些其他要求,我编写了一个小型库来进行位操作。如果你对它感兴趣,请访问:http://github.com/wroniasty/bits。干杯。 – wroniasty

+0

没问题。并感谢您的信用。 – QuasarDonkey

1

特定位设置为1,您可以创建一系列的都是0,除了要设置的那些位(这些都是1),并与现有的位OR它。要设置特定位为0,你做同样的事情,只有在所有位是1,除了你想0的那些和你使用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 

不知道任何库的帮助,虽然。

+0

当然,对于如何有效计算这些蒙版有什么建议是正确的? – wroniasty