3

メモリバッファの指定されたビットオフセットで、指定されたビット長(必ずしも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ました。

このタスクを達成/簡素化するために使用できる既存のライブラリはありますか?それを実装することに関する提案はありますか?

4

2 に答える 2

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

コンパイルするには、これらすべてを1つのファイルにダンプしてコンパイルします。テスト実行の出力:

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

役に立った場合、または問題が発生した場合はお知らせください。

于 2012-06-04T00:55:40.677 に答える
1

OR特定のビットを1に設定するには、設定するビット(1)と既存のビットを除いてすべて0である一連のビットを作成できます。特定のビットを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

しかし、それを支援するライブラリはありません。

于 2012-06-03T16:38:46.147 に答える