为什么在内存中的类对象已经是二进制时还需要序列化(C/C++)?

10

我的猜测是数据分散在物理内存中(即使类对象的数据在虚拟内存中是连续的),因此为了正确地发送数据,需要重新组装数据,并且为了能够通过网络发送,还需要将主机字节顺序转换为网络字节顺序。这样理解是否正确?


只是为了明确这一点:这与虚拟内存和物理内存无关。 - TonyK
5个回答

11
适当的序列化可用于将数据发送到可能与源主机不同架构的任意系统。
即使只包含本地类型的对象在两个系统之间共享也可能会有问题,因为成员之间和之后可能存在额外的填充等原因。在为相同架构但使用不同编译器版本的程序之间共享对象的原始内存转储时,也可能会变得非常麻烦。无法保证变量类型T实际上是如何存储在内存中的。
如果您不使用指针(包括引用),并且数据是由与其一起转储的相同二进制文件读取的,则通常可以安全地将原始结构转储到磁盘上,但是当向另一个主机发送数据时... 序列化是正确的方法。
我听说过开发人员谈论ntohl / htonl / ntohl / ntohs作为序列化/反序列化整数的方法,仔细想想,这种说法并不远离真相。
“序列化”一词经常用于描述这种“以通用方式存储数据的复杂方法”,但是,你的第一个编程任务要求你将有关狗的信息保存到文件中(希望)以某种方式使用了序列化。
(*“希望”意味着您没有将Dog对象的原始内存表示转储到磁盘上)

7

指针!

如果你在堆上分配了内存,你最终会得到一个指向任意内存区域的序列化指针。如果你只有一些intchar,那么可以直接将它们写入文件,但这样就会因为字节顺序问题而依赖于平台。


2

指针和数据包(数据对齐)

如果您使用memcpy函数复制对象的内存,可能会复制一个野指针而非数据。还有另一种风险,如果发送方和接收方使用不同的数据包(数据对齐)方法,则在解码后可能会得到垃圾值。


1

二进制表示法在不同的架构、编译器甚至是同一编译器的不同版本之间可能会有所不同。不能保证系统A所看到的有符号整数在系统B上也能被视为相同的值。如果您没有正确定义协议或文件格式来交换数据,字节顺序、字长、结构填充等问题将变得难以调试。


0

当我们谈论C++时,类(Class)也包括虚方法指针 - 它们必须在接收端重建。


3
如果你再解释一些,你其实是对的。带有虚成员的类包含一个隐藏指针(只有一个指向虚方法表的指针!),只有通过调用正确的构造函数才能在接收端正确地设置它。由于该指针包含在类的 sizeof 中,从缓冲区中进行 memcpy 会破坏它,因此必须逐个序列化/反序列化成员(总是可以有一个大的 POD 成员或实际数据的基类)。 - Jan Hudec

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接