0

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

例如:

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>>我得到一个错误

错误:无法将位域 'a.teststruct::a' 绑定到 'quint16& {aka short unsigned int&}'

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

4

2 回答 2

1

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

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在这种情况下最有可能处理的类型之一(您可以在docsquint8中阅读更多信息)。

要修复此行为,您可以将QDataStream::operator<<实现修改为:

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

另一方面,要将数据读取到这种结构中,您应该在QDataStream::operator>>实现中进行类似的更新:

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

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

这样,您就可以用一种方法编写/读取整个结构,而不必担心结构(附加字段)的进一步增长和更新两个运算符的实现。

于 2016-12-01T10:04:45.453 回答
0

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

请注意,该结构的内存布局与其磁盘布局没有任何关系!磁盘布局取决于您如何使用 theQDataStream及其运算符。您展示的磁盘布局浪费了 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)]
于 2016-12-01T15:08:59.913 回答