据我所知,C库提供了序列化数值成非文本的字节流没有任何帮助。 如我错了请纠正我。
使用的最标准的工具是htonl
等人从POSIX。 这些功能都有缺点:
- 有没有64位支持。
- 没有浮点支持。
- 有没有版本符号类型。 反序列化时,将无符号到符号的转换依赖于符号整数溢出是UB。
- 他们的名字没有说明数据类型的大小。
- 它们依赖于8位的字节,并且确切尺寸uint_Ñ_t的存在。
- 输入类型是一样的输出类型,而不是指一个字节流。
- 这要求用户执行的指针类型转换这在对准可能不安全。
- 已经执行的类型转换,用户可能试图在其本机内存布局,一个贫穷的做法,导致意外的错误转换和输出的结构。
用于序列任意大小的接口char
到8位字节的标准将落入在C标准,这并没有真正承认8位字节,以及任何标准(ITU?)设定的八位位组作为发送的基本单位之间。 但旧的标准没有得到修正。
现在,C11有许多可选组件,一个二进制序列扩展可以沿着之类的东西线程被加入,而不会对现有实现的需求。
将这种扩展是有用的,或者担心的非二进制补码机器只是毫无意义?
我从来没有使用过,但我认为谷歌的协议缓冲器满足您的要求。
- 64位类型,符号/无符号,和浮点类型的所有支持 。
- 生成的API是类型安全
- 序列化可以做到/从流
本教程似乎是一个不错的介绍 ,你可以了解实际的二进制存储格式在这里 。
从他们的网页 :
什么是Protocol Buffers的?
协议缓冲区是谷歌的语言中立,平台中立的,可扩展的序列化结构化数据的机制 - XML,但是更小,更快,更简单。 你可以定义你希望你的数据进行一次结构化的,那么你可以使用特殊生成的源代码可以轻松地写入和读取你的结构化数据,并从各种数据流,并使用各种语言 - 的Java,C ++或Python。
有一个在纯C(仅C ++)没有正式实施,但也有可能会满足您的需求两个C端口:
我不知道他们在非8位字节的存在表现如何,但它应该是比较容易发现。
在我看来像功能的主要缺点htonl()
是他们只做了一半的工作是什么系列化。 他们只翻转字节的多字节整数,如果你的机器是小端。 必须序列化时所做的其他重要的事情是处理比对,而这些功能不这样做。
很多的CPU不能够(高效地)访问没有存储在存储器位置,其地址不在字节整数的大小的倍数的多字节整数。 这是从来没有使用结构覆盖到(反)序列化的网络数据包的原因。 我不知道如果这是你的“就地转化”的意思。
我工作了很多嵌入式系统,和我在我自己的库函数生成或时我总是用解析网络数据包(或任何其他I / O:磁盘,RS232等):
/* Serialize an integer into a little or big endian byte buffer, resp. */
void SerializeLeInt(uint64_t value, uint8_t *buffer, size_t nrBytes);
void SerializeBeInt(uint64_t value, uint8_t *buffer, size_t nrBytes);
/* Deserialize an integer from a little or big endian byte buffer, resp. */
uint64_t DeserializeLeInt(const uint8_t *buffer, size_t nrBytes);
uint64_t DeserializeBeInt(const uint8_t *buffer, size_t nrBytes);
除了这些功能,还有一堆定义suchs为宏:
#define SerializeBeInt16(value, buffer) SerializeBeInt(value, buffer, sizeof(int16_t))
#define SerializeBeUint16(value, buffer) SerializeBeInt(value, buffer, sizeof(uint16_t))
#define DeserializeBeInt16(buffer) DeserializeBeType(buffer, int16_t)
#define DeserializeBeUint16(buffer) DeserializeBeType(buffer, uint16_t)
(解)序列化功能读取或写入的字节的值字节,所以对准问题将不会发生。 你并不需要担心的符号性无论是。 首先所有的系统,这些天使用二进制补码(除了也许几个模数转换器,但你不会使用这些功能)。 但是,应该在系统上使用1的补,因为即使工作(据我所知)一个有符号整数转换为2秒时,铸造无符号(和函数接受/返回无符号整数)补充。
你另一种说法是,他们依靠8位字节和精确尺寸的存在uint_N_t
。 这也算我的功能,但在我看来,这不是一个问题(这些类型总是和我一起工作的系统和他们的编译器定义)。 你可以调整的函数原型使用unsigned char
,而不是uint8_t
之类的东西long long
或uint_least64_t
代替uint64_t
,如果你喜欢。
见XDR库和XDR标准RFC-1014 RFC-4506