在C ++中将结构体写入字符串流

时间:2014-05-28 07:30:11

标签: c++ stringstream

我有一些结构:

struct dHeader
{
    uint8_t    blockID;
    uint32_t   blockLen;
    uint32_t   bodyNum;
};
struct dBody
{
    char       namestr[10];
    uint8_t    blk_version;
    uint32_t   reserved1;
}

我有一个字符串流:

std::stringstream Buffer(std::iostream::in | std::iostream::out);

我想用

将一个dHdr和多个dBody结构写入Buffer
Buffer << Hdr1;
Buffer << Body1;
Buffer << Body1;

我收到错误:

  

错误:&#39;运营商&lt;&lt;&lt;&#在&#39;缓冲区&lt;&lt; HDR1&#39;

如果我尝试使用:

Buffer.write(reinterpret_cast<char*>(&Hdr1), sizeof(dbHdr1));
Buffer.write(reinterpret_cast<char*>(&Body1), sizeof(Body1));
Buffer.write(reinterpret_cast<char*>(&Body2), sizeof(Body2));

我对打包和内存对齐感到困惑。

  • 将结构体写入字符串流的最佳方法是什么?
  • 阅读 将stringstream转换为常规字符串?

2 个答案:

答案 0 :(得分:3)

对于每个结构,您需要定义类似于此的内容:

struct dHeader
{
    uint8_t    blockID;
    uint32_t   blockLen;
    uint32_t   bodyNum;
};

std::ostream& operator<<(std::ostream& out, const dHeader& h)
{
     return out << h.blockID << " " << h.blockLen << " " << h.bodyNum;
}

std::istream& operator>>(std::istream& in, dHeader& h) // non-const h
{
    dHeader values; // use extra instance, for setting result transactionally
    bool read_ok = (in >> values.blockID >> values.blockLen >> values.bodyNum);

    if(read_ok /* todo: add here any validation of data in values */)
        h = std::move(values);
    /* note: this part is only necessary if you add extra validation above
    else
        in.setstate(std::ios_base::failbit); */
    return in;
}

(与其他结构相似)。

编辑:未缓冲的读/写实现具有以下缺点:

  • 没有格式化;对于小型实用程序应用程序而言,这可能不是问题,如果您控制它的编译和运行位置,但通常情况下,如果您获取序列化数据并在不同的体系结构上运行/编译应用程序,您将遇到字节序问题;您还需要确保您使用的类型不依赖于架构(即继续使用uintXX_t类型)。

  • 它很脆弱;实现取决于仅包含POD类型的结构。如果稍后在结构中添加char *,则代码将编译相同的内容,只显示未定义的行为。

  • 它是模糊的(您的代码的客户端希望看到为I / O定义的接口或假设您的结构不支持序列化)。通常,没有人认为“也许我可以序列化,但使用未缓冲的I / O” - 至少在作为自定义结构或类实现的客户端时是这样。

可以通过添加i / o流运算符来改善可以的问题,这些运算符是根据未缓冲的读写实现的。

上述运算符的示例代码:

std::ostream& operator<<(std::ostream& out, const dHeader& h)
{
     out.write(reinterpret_cast<char*>(&h), sizeof(dHeader));
     return out;
}

std::istream& operator>>(std::istream& in, dHeader& h) // non-const h
{
    dHeader values; // use extra instance, for setting result transactionally
    bool read_ok = in.read( reinterpret_cast<char*>(&values), sizeof(dHeader) );

    if(read_ok /* todo: add here any validation of data in values */)
        h = std::move(values);
    /* note: this part is only necessary if you add extra validation above
    else
        in.setstate(std::ios_base::failbit); */
    return in;
}

这会集中接口背后的代码(即如果您的类不再支持非缓冲写入,则必须更改一个位置中的代码),并使您的意图显而易见(实现序列化为你的结构)。它仍然很脆弱,但不那么容易。

答案 1 :(得分:1)

您可以为std::ostream::operator<<提供过载,例如

std::ostream& operator<<(std::ostream&, const dHeader&);
std::ostream& operator<<(std::ostream&, const dBody&);

有关详细信息,请参阅此stackoverflow question