据我所知,C库在将数值序列化为非文本字节流方面没有提供任何帮助。如果我错了就纠正我。
使用中最标准的工具是来自POSIX的htonl等人。这些职能存在缺陷:
将任意大小的char序列化为8位标准字节的接口将位于C标准之间,C标准并不真正承认8位字节,与其他标准(ITU?)将八进制设为传输的基本单位。但是旧的标准并没有被修改。
既然C11有许多可选组件,就可以在线程的旁边添加二进制序列化扩展,而无需对现有实现提出要求。
这样的扩展是有用的,还是担心非二补机器就那么毫无意义?
发布于 2012-07-24 01:50:22
我从未使用过它们,但我认为谷歌的协议缓冲器满足了您的需求。
本教程似乎是个很好的介绍,您可以阅读有关实际二进制存储格式这里。
从他们的网页
什么是协议缓冲区? 协议缓冲区是Google的语言中立的、平台中立的、可扩展的序列化结构化数据的机制--考虑XML,但更小、更快、更简单。您可以定义您希望您的数据被构造一次的方式,然后您可以使用特殊生成的源代码来轻松地在各种数据流之间以及使用各种语言-- Java、C++或Python --之间编写和读取结构化数据。
纯C中没有正式的实现(只有C++),但是有两个C端口可能适合您的需要:
我不知道在非8位字节的情况下,它们的表现如何,但是应该比较容易找到。
发布于 2012-07-23 13:56:10
在我看来,像htonl()这样的函数的主要缺点是它们只完成了一半的工作,这就是序列化。它们只在机器是小endian的情况下翻转多字节整数中的字节。序列化时必须做的另一件重要事情是处理对齐,而这些函数不这样做。
许多CPU无法(有效)访问多字节整数,这些整数没有存储在内存位置,而内存位置的地址不是整数大小的倍数(以字节为单位)。这就是为什么从不使用struct覆盖来(反)序列化网络数据包的原因。我不知道这是不是你所说的“就地转换”的意思。
我经常使用嵌入式系统,并且在我自己的库中有一些函数,在生成或解析网络数据包(或任何其他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);除了这些函数之外,还有一组宏定义为:
#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)(反序列化函数逐字节读取或写入值,因此不会出现对齐问题。你也不用担心手语的问题。首先,现在所有的系统都使用2s补码(除了一些ADC之外,但是你不会使用这些功能)。然而,它甚至应该在使用1s补码的系统上工作,因为(据我所知)有符号整数在转换为无符号时被转换为2s补码(并且函数接受/返回无符号整数)。
您的另一个参数是,它们依赖于8位字节和精确大小的uint_N_t。这对我的功能也很重要,但在我看来,这不是一个问题(这些类型总是为我所使用的系统及其编译器定义的)。如果您愿意,可以调整函数原型,使其使用unsigned char而不是uint8_t,也可以使用long long或uint_least64_t之类的东西来代替uint64_t。
https://stackoverflow.com/questions/11500425
复制相似问题