Frage

Ich habe eine unsigned char Puffer, und ich frage mich, wie ich schreiben würde, und mit und ohne Vorzeichen Bits in diesem Byte-Puffer lesen.

Source Engine gibt es eine Klasse mit dem Namen bf_write , die zwei Hauptverfahren (verwendet von Write, writeChar, WriteLong, etc.) verwenden, um zwei Funktionen mit dem Namen WriteUBitLong und WriteSBitLong .

Vielen Dank im Voraus

War es hilfreich?

Lösung

Wenn die Anzahl der Bits ist eine Kompilierung-Konstante:

#include <bitset>
...
std::bitset<100> b;
b[2]=true;

Wenn es nicht benutzen Boost.dynamic_bitset

Oder, wenn Sie sind verzweifelt, std :: vector, die in der Tat ist eine gepackte Bitvektor:

#include <vector>
...
std::vector<bool> b(100);
b[2]=true;

Sie scheinen zu wollen, um eine Bibliothek verwenden, die in einem Array von Bytes gepackt Bit-Vektoren erfordern. Ohne genau zu wissen, in welcher Reihenfolge sie die Bits in platziert kann ich nur, dass beachten Sie:

1) alle oben wahrscheinlich mindestens 32-Bit ints mit Bits verwenden bestellt am wenigsten> die meisten oder die Meist> niedrigstwertigen

2) auf Little-Endian (Intel / AMD) CPUs, bedeutet dies, dass der Speicher durch die Bytes belegt ein Array von ints nicht mit der Bestellung von Bits innerhalb des int konsistent sein kann. wenn es "Bit 0 das lsb von int 0, ... Bit 32 das ist lsb von int 1, ...", dann ist das das gleiche in Little-Endian als „Bit 0 das lsb von char 0 ... Bit 32 ist die lsb von char 4 ... ", in dem Fall, dass Sie nur einen Zeiger auf das int-Array zu einem Zeiger werfen können Array auf char

3) angenommen, die native Reihenfolge des Bytes in Ihrem Bit gesetzt / Vektor ist nicht genau das, was die Bibliothek benötigt, dann müssen Sie entweder Ihre eigenen erstellen, die das Layout hat sie will, oder eine Kopie in ihrem Layout transkribieren .

a) wenn die Reihenfolge der Bits innerhalb eines Bytes verschieden ist, eine 256 Eintrag Lookup-Tabelle das Byte mit Bits umgekehrt zu geben wäre effizienter. Sie können die Tabelle mit einer kleinen Routine erzeugen.

b) zu umkehren Bytes aus wenig <-> Big-Endian:

inline void endian_swap(unsigned short& x)
{
    x = (x>>8) | 
        (x<<8);
}

inline void endian_swap(unsigned int& x)
{
    x = (x>>24) | 
        ((x<<8) & 0x00FF0000) |
        ((x>>8) & 0x0000FF00) |
        (x<<24);
}    

inline void endian_swap(unsigned long long& x)
{
    x = (x>>56) | 
        ((x<<40) & 0x00FF000000000000) |
        ((x<<24) & 0x0000FF0000000000) |
        ((x<<8)  & 0x000000FF00000000) |
        ((x>>8)  & 0x00000000FF000000) |
        ((x>>24) & 0x0000000000FF0000) |
        ((x>>40) & 0x000000000000FF00) |
        (x<<56);
}

Um ein bestimmtes Bit innerhalb eines Wortes, mit Bit # 0 in das niedrigstwertige Bit des Wortes 0 zu erhalten / set:

typedef unsigned char block_t;
const unsigned block_bits=8;

inline void set_bit(block_t *d,unsigned i) {
  unsigned b=i/block_bits;
  unsigned bit=i-(block_bits*b); // same as i%b
  block_t &bl=d[b];
  bl|=(1<<bit); // or bit with 1 (others anded w/ 0)
}

inline void clear_bit(block_t *d,unsigned i) {
  unsigned b=i/block_bits;
  unsigned bit=i-(block_bits*b); // same as i%b
  block_t &bl=d[b];
  bl&=(~(1<<bit)); // and bit with 0 (other bits anded w/ 1)
}

inline void modify_bit(block_t *d,unsigned i,bool val) {
  if (val) set_bit(d,i) else clear_bit(d,i);
}

inline bool get_bit(block_t const* d,unsigned i) {
  unsigned b=i/block_bits;
  unsigned bit=i-(block_bits*b); // same as i%b
  return d[b]&(1<<bit);
}

Natürlich, wenn die Regel für Bitorganisation unterscheidet, müssen Sie die oben ändern.

Mit der größtmöglichen int Ihre CPU Prozesse effizient wie block_t am besten ist (nicht‘vergessen block_bits zu ändern), es sei denn, die endianness nicht klappt w / der Bibliothek Sie verwenden.

Andere Tipps

Ich denke, ein paar Makros sind genug:

#define set_bit0(buf, i) ((buf)[(i)/8]&=~(1u<<(i)%8))
#define set_bit1(buf, i) ((buf)[(i)/8]|=1<<(i)%8)
#define get_bit(buf, i) ((buf)[(i)/8]>>(i)%8&1)

Darüber hinaus tauschen endianness kann in einem schnelleren Weg erfolgen. Zum Beispiel für eine 64-Bit-Integer-v, tauschen die folgenden Operationen seine endianness:

v = ((v & 0x00000000FFFFFFFFLLU) << 32) | (v >> 32);
v = ((v & 0x0000FFFF0000FFFFLLU) << 16) | ((v & 0xFFFF0000FFFF0000LLU) >> 16);
v = ((v & 0x00FF00FF00FF00FFLLU) << 8) | ((v & 0xFF00FF00FF00FF00LLU) >> 8);
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top