Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
可移植C二进制序列化原语_C_Portability_Binaryfiles_Endianness_Htonl - Fatal编程技术网

可移植C二进制序列化原语

可移植C二进制序列化原语,c,portability,binaryfiles,endianness,htonl,C,Portability,Binaryfiles,Endianness,Htonl,据我所知,C库在将数值序列化为非文本字节流方面没有提供任何帮助。如果我错了,请纠正我 使用中最标准的工具是POSIX中的et al。这些功能都有缺点: 不支持64位 不支持浮点运算 没有签名类型的版本。反序列化时,无符号到有符号的转换依赖于有符号整数溢出,即UB 它们的名称不表示数据类型的大小 它们取决于8位字节和确切大小uint的存在 输入类型与输出类型相同,而不是引用字节流。 这需要用户执行指针类型转换,这在对齐时可能不安全 执行了该类型转换后,用户可能会尝试转换并输出其本机内存布局中的

据我所知,C库在将数值序列化为非文本字节流方面没有提供任何帮助。如果我错了,请纠正我

使用中最标准的工具是POSIX中的et al。这些功能都有缺点:

  • 不支持64位
  • 不支持浮点运算
  • 没有签名类型的版本。反序列化时,无符号到有符号的转换依赖于有符号整数溢出,即UB
  • 它们的名称不表示数据类型的大小
  • 它们取决于8位字节和确切大小uint的存在
  • 输入类型与输出类型相同,而不是引用字节流。
    • 这需要用户执行指针类型转换,这在对齐时可能不安全
    • 执行了该类型转换后,用户可能会尝试转换并输出其本机内存布局中的结构,这是一种糟糕的做法,会导致意外错误
将任意大小的字符串行化为8位标准字节的接口将介于C标准(实际上不承认8位字节)和任何标准(ITU?)之间,后者将八位字节设置为基本传输单元。但旧的标准没有得到修订

既然C11有许多可选组件,那么可以在线程之类的东西旁边添加二进制序列化扩展,而无需对现有实现提出要求


这样的扩展有用吗,还是担心非二元补码机器就没有意义了?

在我看来,像
htonl()
这样的函数的主要缺点是它们只做了序列化的一半工作。如果您的机器是little endian,则它们仅翻转多字节整数中的字节。序列化时必须做的另一件重要的事情是处理对齐,而这些函数不这样做

许多CPU不能(有效地)访问多字节整数,这些整数不存储在地址不是整数(字节)大小的倍数的内存位置。这就是永远不要使用结构覆盖来(反)序列化网络数据包的原因。我不确定这是否就是你所说的“就地转换”的意思

我经常使用嵌入式系统,我在自己的库中有函数,在生成或解析网络数据包(或任何其他I/O:disk、RS232等)时总是使用这些函数:

除了这些函数外,还有一系列宏,定义如下:

#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位字节和确切大小的存在。这对我的函数也很重要,但我认为这不是问题(这些类型总是为我使用的系统及其编译器定义的)。你可以调整函数原型,用
无符号字符来代替
uint8\u t
,或者像
long
或者
uint\u-least64\u t
之类的东西来代替
uint64\u t
,如果你愿意的话。

请看库和XDR标准。

我从来没有用过它们,但我认为谷歌满足你的要求

  • 支持64位类型、有符号/无符号和浮点类型
  • 生成的API是类型安全的
  • 可以对流进行序列化/从流进行序列化
这是本教程,您可以阅读有关实际二进制存储格式的内容


从他们的:

什么是协议缓冲区

协议缓冲区是Google用于序列化结构化数据的语言中立、平台中立、可扩展的机制——比如XML,但更小、更快、更简单。您定义了如何希望将数据结构化一次,然后可以使用特殊生成的源代码来轻松地编写和读取各种数据流和使用各种语言——java、C++或Python。 纯C中没有正式的实现(只有C++),但有两个C端口可以满足您的需要:

  • 纳米Pb,at

  • Protobuf-c at


我不知道在存在非8位字节的情况下它们的表现如何,但应该相对容易找到。

关于
hton?
/
ntoh?
和名称中的大小,实际上大小是名称中的大小。最后一个字母是大小,
s
表示
short
l
表示
long
@JoachimPileborg,除了
long
在许多系统中是64位的,而具有非8位字节的系统不可能完全匹配16位
short
或32位
long
。C标准故意含糊其辞,它可以作为一个外部库,用于它可能工作的平台。我看不出这门语言能从中赢得什么。如果我在IBM大型机上,接收IEEE浮点格式是没有用的。文本表示将更易于处理。您的可移植性要求非IEEE系统支持与非本机浮点格式之间的转换。这不是我想要的语言标准;它们返回转换后的结果而不更改输入值,但它看起来更像是
htonl
的高级包装器,而不是更便携的替代品。出于某种原因,他们没有用数字命名数据类型。我不明白Linux API如何可以移植,因为
xdr\l
#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)