Es ist immer noch nicht klar, ob diese ist ein Dateiformat, das Sie steuern, oder wenn es etwas anderes ist. Wie auch immer, lassen Sie uns annehmen, dass Sie einige Integer-Datentyp haben, der einen 36-Bit-Wert ohne Vorzeichen halten kann:
typedef uint64_t u36;
Nun, unabhängig davon, ob Ihr System verwendet Big-Endian oder Little-Endian, können Sie den Wert auf einen Schreib Binärstrom in einer vorhersagbaren Reihenfolge, indem Sie sie ein Byte nach dem anderen tun. Lassen Sie uns Big-Endian verwenden, weil es etwas einfacher ist, sich die zusammengesetzten Bits vorzustellen, um einen Wert zu erzeugen.
Sie können nur naive Verschiebung und Maskierung in einen kleinen Puffer verwenden. Das einzige, was zu entscheiden ist, wo das Halbbyte abgeschnitten wird. Aber wenn Sie dem Muster folgen, bei dem jeder Wert um weitere 8 Bits verschoben wird, dann fällt der Rest natürlich in die höhere Ordnung.
ostream & write_u36(ostream & s, u36 val)
{
char bytes[5] = {
(val >> 28) & 0xff,
(val >> 20) & 0xff,
(val >> 12) & 0xff,
(val >> 4) & 0xff,
(val << 4) & 0xf0
};
return s.write(bytes, 5);
}
Aber das ist nicht, wie Sie tatsächlich eine Reihe dieser Zahlen schreiben würden. Sie müßten das 5. Byte abwarten, bis Sie fertig waren oder Sie könnten den nächsten Wert hinein packen. Oder Sie würden immer zwei Werte in einer Zeit schreiben:
ostream & write_u36_pair(ostream & s, u36 a, u36 b)
{
char bytes[9] = {
(a >> 28) & 0xff,
(a >> 20) & 0xff,
(a >> 12) & 0xff,
(a >> 4) & 0xff,
(a << 4) & 0xf0 | (b >> 32) & 0x0f,
(b >> 24) & 0xff,
(b >> 16) & 0xff,
(b >> 8) & 0xff,
b & 0xff
};
return s.write(bytes, 9);
}
Und jetzt, könnte man sehen, wie man über Lesen Werte und deserialising sie wieder in ganzen Zahlen. Der einfachste Weg ist, zwei gleichzeitig zu lesen.
istream & read_u36_pair(istream & s, u36 & a, u36 & b)
{
char bytes[9];
if(s.read(bytes, 9))
{
a = (u36)bytes[0] << 28
| (u36)bytes[1] << 20
| (u36)bytes[2] << 12
| (u36)bytes[3] << 4
| (u36)bytes[4] >> 4;
b = ((u36)bytes[4] & 0x0f) << 32
| (u36)bytes[5] << 24
| (u36)bytes[6] << 16
| (u36)bytes[7] << 8
| (u36)bytes[8];
}
return s;
}
Wenn man ihnen einen nach dem anderen lesen wollte, dann würden Sie den Überblick über einigen Zustand zu halten, müssen so wußte man, wie viele Bytes (entweder 5 oder 4) zu lesen, und die Operationen verschieben anzuwenden.Etwas naiv wie folgt aus:
struct u36deser {
char bytes[5];
int which = 0;
};
istream & read_u36(istream & s, u36deser & state, u36 & val)
{
if(state.which == 0 && s.read(state.bytes, 5))
{
val = (u36)state.bytes[0] << 28
| (u36)state.bytes[1] << 20
| (u36)state.bytes[2] << 12
| (u36)state.bytes[3] << 4
| (u36)state.bytes[4] >> 4;
state.which = 1;
}
else if(state.which == 1 && s.read(state.bytes, 4))
{
val = ((u36)state.bytes[4] & 0x0f) << 32 // byte left over from previous call
| (u36)state.bytes[0] << 24
| (u36)state.bytes[1] << 16
| (u36)state.bytes[2] << 8
| (u36)state.bytes[3];
state.which = 0;
}
return s;
}
All dies ist rein hypothetisch, was der Punkt Ihrer Frage ohnehin zu sein scheint. Es gibt viele andere Möglichkeiten, Bits zu serialisieren, und einige von ihnen sind überhaupt nicht offensichtlich.
Es liegt ganz bei Ihnen zu entscheiden, welche Bits in einem Byte zuerst kommen. –
Sie müssen 'readHere' als 'uint64_t' (oder etwas größer) deklarieren, um 5 Bytes darin zu speichern. – TriskalJM
ja, vergaß es, danke ich werde es beheben. – Darlyn