我有一个数据字节数组,应该是跨平台的一致。假设我有一个指针unsigned char* data
,它指向我的数组中的某个位置,我想将4个字节读入变量。我认为我可以这样做:
uint32_t my_int = *data;
但是,我意识到该方法不考虑字节序。例如,如果我的数据是big endian,我是否必须这样做才能一致地读取它?
uint32_t my_int = (data[0] << 3) + (data[1] << 2) + (data[2] << 1) + data[3];
同样,在使用fwrite
编写此数据时,是否必须进行相同的检查?例如,如果我使用此代码将相同的数据写入文件:
fwrite(&my_int, sizeof(my_int), 1, fh);
结果数据是否具有任何已知的字节序?或者它会依赖于建筑?如果是这样,在所有平台上执行这些读写操作以及强制执行特定字节序的最简单方法是什么?
答案 0 :(得分:3)
每当读取或写入二进制数据时,您都需要担心字节序。如果您尝试读取/写入整个结构,还需要担心可变大小和可能的结构打包。有些架构也无法处理奇数变量边界上的整数,因此您不能使用uint32_t myInteger = *(uint32_t *)bufferPtr ++等函数直接从二进制缓冲区中获取整数。
有各种方法可以完成这项工作。在过去,当速度和RAM使用是一个巨大的问题时,我们会直接从文件中读取一大块数据到缓冲区,然后根据需要使用指向结构的指针固定端点。
你今天仍然可以这样做,虽然编译器之间的结构打包差异使得它很麻烦,因此为特定类型编写一些简单的i / o例程可能更有意义,例如
int write_integer_at_position( FILE *, size_t position, uint32_t );
int read_integer_from_position( FILE *, size_t position, uint32_t *outResult );
etc
如果需要,这些例程可以在读取之后或在将数据写入磁盘之前交换字节,可能使用htonl。完成20或30次之后,您可能希望编写某种数据描述语言来映射RAM和文件中的结构。很多人都这样做了,但我认为没有人特别喜欢。
答案 1 :(得分:1)
答案 2 :(得分:1)
这些是您在数据输出或进入应用程序时遇到的典型问题。如果数据的生产者和消费者只是您的应用程序,那么它就不是问题了。
但是,正如EricS所提到的,如果有其他应用程序将使用或生成此数据,并且这些应用程序位于不同的平台/语言/框架上,那么您的序列化或反序列化的字节顺序肯定很重要。
网络订单是一种在基于IP的协议上使用的事实上的标准。库函数可以从主机转换为网络,网络转换为主机订单(参见Ed Heal提供的链接)。
除了字节顺序之外,您可能还必须根据协议和平台查看位顺序,最高有效位或最低有效位可能首先在线上被推出。
结构的包装,类型的表示(整数,字符串,字符),其大小等也可能需要考虑。