2016-12-01 4 views
0

Ich versuche, Bitfelder Struktur in Datei schreiben und dann lesen.Schreiben/Lesen Bitfelder Struktur zu/von Datei

Zum Beispiel:

typedef struct{ 
    ushort 
       a:4, 
       b:4, 
       c:4, 
       d:4; 
} teststruct; 

Ich versuche zu schreiben und es wie dieser

QDataStream &operator <<(QDataStream &st, const teststruct &a) 
{ 
    st <<a.a << a.b << a.c << a.d; 
    return st; 
} 

QDataStream &operator >>(QDataStream &st, teststruct &a) 
{ 
    st >>a.a >> a.b >> a.c >> a.d; 
    return st; 
} 

teststruct str1, str2; 
str1.a = 1; 
str1.b = 0; 
str1.c = 1; 
str1.d = 0; 

QFile f("testfile"); 
f.open(QFile::WriteOnly); 
QDataStream st(&f); 

st << str1; 
f.close(); 
f.open(QFile::ReadOnly); 
QDataStream st(&f); 
st >> str2; 
f.close(); 

Aber in QDataStream::operator>> bekam las ich einen Fehler

error: cannot bind bitfield 'a.teststruct::a' to 'quint16& {aka short unsigned int&}'

Was kann ich mit >> tun Operator oder vielleicht gibt es eine andere Möglichkeit, Daten in meine Struktur zu lesen?

+0

Sie können keine nicht-const Verweis auf eine bit- haben Feld. 'QDataStream :: operator >> (quint16 & i)' nimmt den Parameter als eine nicht-konstante Referenz (wie die Fehlermeldung, die Sie erhalten, zeigt), deshalb erhalten Sie den Fehler. – thuga

Antwort

0

In Ihrem Beispiel sollten Sie feststellen, dass die in der Datei gespeicherten Daten wahrscheinlich falsch sind. So zum Beispiel mit der folgenden Struktur:

struct BitStruct 
{ 
    uint8_t  b1:4; 
    uint8_t  b2:4; 
}; 

und den Bediener geschrieben wie:

QDataStream &operator <<(QDataStream &st, const BitStruct &a) 
{ 
    st <<a.b1 << a.b2; 
    return st; 
} 

, wenn Sie Beispieldaten schreiben BitStruct bits{0x1, 0x2}; Datei Sie 2 Bytes geschrieben haben. Binär Inhalt der Datei wäre 0x01 0x02 was wahrscheinlich nicht das ist, was Sie erreichen möchten.

Es kommt aufgrund der Tatsache, dass Aufruf st << a.b1 Ergebnisse im b1 Feld zu einem der von QDataStream behandelt Typen umgewandelt werden, die in diesem Fall höchstwahrscheinlich quint8 (Sie können mehr in docs lesen).

dieses Problem zu beheben, können Sie die QDataStream::operator<< Implementierung ändern:

st.writeRawData(reinterpret_cast<const char*>(&a), sizeof(BitStruct)); 

Auf der anderen Seite, die Daten auf eine solche Struktur lesen Sie in der QDataStream::operator>> Implementierung ein ähnliches Update tun sollten:

st.readRawData(reinterpret_cast<char*>(&a), sizeof(BitStruct)); 

Dies würde erlauben, die Struktur in einer kompakten Weise wie beabsichtigt zu schreiben und bestimmte Bitfelder entsprechend zu lesen.

Auf diese Weise haben Sie Ihre ganze Struktur in einem einzigen Ansatz geschrieben/gelesen und müssen sich keine Gedanken über das weitere Wachstum der Struktur (zusätzliche Felder) und die Aktualisierung beider Betreiberimplementierungen machen.

0

Ich nehme an, dass der Grund, warum Sie Ihre Bitfield-Struktur haben, ist, dass seine Größe ist die von ushort (wirklich uint16_t), und es um Wert ist preisgünstig und es dauert den minimalen Speicherplatz möglich. Das ist ein guter Grund, also lass uns damit anfangen.

Beachten Sie, dass das speicherinterne Layout der Struktur nichts mit dem Layout auf der Festplatte zu tun hat! Das Layout auf der Festplatte hängt davon ab, wie Sie die und ihre Operatoren verwenden. Die Festplatten-Layout, wie Sie zeigen es 75% Platz verschwendet - jeder Wert nimmt 16 Bit, aber es braucht nur 4:

(uint16_t a) (uint16_t b) (uint16_t c) (uint16_t d) 

Der Schlüssel zu fixieren Zwischenwerte als Schnittstelle zwischen der Struktur zu verwenden ist und die Datenstrom.

So:

QDataStream &operator <<(QDataStream &st, const teststruct &a) 
{ 
    uint8_t v0 = (a.d << 4) | a.c; 
    uint8_t v1 = (a.b << 4) | a.a; 
    st << v0 << v1; 
    return st; 
} 

QDataStream &operator >>(QDataStream &st, teststruct &a) 
{ 
    uint8_t v0, v1; 
    st >> v0 >> v1; 
    a.a = v1; 
    a.b = v1>>4; 
    a.c = v0; 
    a.d = v0>>4; 
    return st; 
} 

Die On-Disk-Layout jetzt keinen Platz verschwendet, und ist wie folgt (unter Verwendung von Pseudotypen):

[(uint4_t d) (uint4_t c)] [(uint4_t b) (uint4_t a)]