在我目前的项目中,我有一些不同的接口,要求我将消息序列化为字节缓冲区。我觉得我可能不会以一种让真正的C ++程序员开心的方式来做这件事(而且我也愿意)。
我通常会这样做:
struct MyStruct {
uint32_t x;
uint64_t y;
uint8_t z[80];
};
uint8_t* serialize(const MyStruct& s) {
uint8_t* buffer = new uint8_t[sizeof(s)];
uint8_t* temp = buffer;
memcpy(temp, &s.x, sizeof(s.x));
temp += sizeof(s.x);
//would also have put in network byte order...
... etc ...
return buffer;
}
请原谅任何拼写错误,这只是我头脑中的一个例子。显然,如果我正在序列化的结构有内部指针,它会变得更复杂。
所以,我有两个密切相关的问题:
上面的具体方案是否存在任何问题,通过将结构直接转换为char缓冲区进行序列化,假设我知道目标系统具有相同的字节顺序?
主要问题:有没有更好......呃...... C ++?除了添加智能指针之外,还能做到这一点吗?我觉得这是一个常见的问题,STL可能会处理它 - 如果没有,我相信无论如何使用C ++机制都有更好的方法。
编辑如果您可以使用标准C ++ / STL以更好的方式更新序列化此结构,而不添加库,则可获得加分。
答案 0 :(得分:6)
您应该可以直接使用Boost :: serialization或流。右侧链接中的更多信息。
答案 1 :(得分:6)
您可能需要查看Google Protocol Buffers(也称为protobuf)。您可以使用语言中性IDL定义数据,然后通过生成器运行它以生成C ++类。它会处理字节排序问题,并且可以提供非常紧凑的二进制形式。
通过使用它,您不仅可以保存C ++数据,而且可以在其他语言(C#,Java,Python等)中使用,因为有可用的protobuf实现。
答案 2 :(得分:1)
刚刚投票选出AzPs作为答案,首先检查Boost是否可行。
另外还有关于您的代码示例:
1 - 将序列化功能的签名更改为采用文件的方法:
void MyStruct::serialize(FILE* file) // or stream
{
int size = sizeof(this);
fwrite(&size, sizeof(int), 1, file); // write size
fwrite(this, 1, size, file); // write raw bytes of struct
}
减少了复制结构的必要性。
2 - 是的,您的代码使序列化字节依赖于您的平台,编译器和编译器设置。这不是好事或坏事,如果相同的二进制文件写入和读取序列化字节,由于简单性和性能,这可能是有益的。但它不仅包括字节序,包装和结构布局也会影响兼容性。例如,您的应用程序的32位或64位版本将确保更改我们的结构的布局。最后,序列化原始足迹还会序列化填充字节 - 编译器可能在结构字段之间放置的字节,这对于高流量网络流来说是一种不利的开销(请参阅google协议缓冲区,因为它们可以保存每一点)。
编辑:
我看到你添加了“嵌入式”。是的,那么这样简单的序列化/反序列化(上面序列化的镜像实现)方法可能是一个很好而简单的选择。