向/从文件写入/读取位字段结构

时间:2016-12-01 09:02:33

标签: qt bit-fields qfile qdatastream

我正在尝试将位字段结构写入文件然后读取它。

例如:

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

我尝试像这样写作和阅读

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

但在QDataStream::operator>>我收到了错误

  

错误:无法绑定位域&#39; a.teststruct :: a&#39;到&#39; quint16&amp; {又简称   unsigned int&amp;}&#39;

我可以使用>>运算符做什么,或者可能有其他方法将数据读取到我的结构中?

2 个答案:

答案 0 :(得分:0)

在您的示例中,您应该注意到保存到文件的数据可能不正确。例如,具有以下结构:

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

并且操作符写为:

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

将样本数据BitStruct bits{0x1, 0x2};写入文件时,将写入2个字节。文件的二进制内容为0x01 0x02,这可能不是您想要达到的目的。

这是因为调用st << a.b1会导致b1字段转换为QDataStream处理的类型之一,在这种情况下很可能是quint8 QDataStream::operator<< (你可以在docs中阅读更多内容。)

要解决此问题,您可以将st.writeRawData(reinterpret_cast<const char*>(&a), sizeof(BitStruct)); 实施修改为:

QDataStream::operator>>

另一方面,要将数据读取到此类结构,您应该在st.readRawData(reinterpret_cast<char*>(&a), sizeof(BitStruct)); 实现中执行类似的更新:

cipher text

这将允许按照预期的紧凑方式编写结构并相应地读取特定的位字段。

通过这种方式,您可以在单一方法中编写/读取整个结构,并且不必担心结构的进一步增长(其他字段)并更新两个运算符实现。

答案 1 :(得分:0)

我认为你拥有你的位域结构的原因是它的大小是ushort(真的uint16_t),并且通过值传递它是便宜的并且它需要尽可能小的空间。这是一个正当的理由,所以让我们继续吧。

请注意,结构的内存布局与磁盘布局没有任何关系!磁盘布局取决于您使用QDataStream及其运算符的方式。显示它时的磁盘布局浪费了75%的空间 - 每个值占用16位,但它只需要4:

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

修复它的关键是使用中间值作为结构和数据流之间的接口。

因此:

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

磁盘布局现在不浪费空间,如下(使用假型):

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