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

Posted

技术标签:

【中文标题】向/从文件写入/读取位域结构【英文标题】:Write/Read bit fields structure to/from file 【发布时间】:2016-12-01 09:02:33 【问题描述】:

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

例如:

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&gt;&gt; 中出现错误

错误:无法将位域 'a.teststruct::a' 绑定到 'quint16& aka short 无符号整数&'

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

【问题讨论】:

您不能对位域进行非常量引用。 QDataStream::operator&gt;&gt;(quint16 &amp;i) 将参数作为非常量引用(如您收到的错误消息所示),这就是您收到错误的原因。 【参考方案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 bits0x1, 0x2; 写入文件时,您将写入 2 个字节。文件的二进制内容为0x01 0x02,这可能不是您想要实现的。

发生这种情况是因为调用st &lt;&lt; a.b1 导致b1 字段被转换为QDataStream 处理的类型之一,在这种情况下很可能是quint8(您可以在@ 中阅读更多信息987654321@).

要解决此问题,您可以将 QDataStream::operator&lt;&lt; 实现修改为:

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

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

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

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

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

【讨论】:

【参考方案2】:

我认为你有你的位域结构的原因是它的大小是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)]

【讨论】:

以上是关于向/从文件写入/读取位域结构的主要内容,如果未能解决你的问题,请参考以下文章

c语言中如何修改储存在文件的结构体内容中。小文件

infos

使用可序列化而不是向/从文件写入和读取对象

C语言复习之直接向文件中写入和读取时间Date对象

在Android中从/向文件读取/写入字符串

同时向 NSMutableArray 写入和读取数据