我目前正在研究一些任意值的二进制文件格式,包括一些字符串和字符串长度值,它们存储为uint32_t
's.
但我想知道,如果我将字符串长度写入fwrite
小端系统上的文件,并在大端系统上从同一个文件中读取该值,fread
字节的顺序会反转吗?如果是这样,解决这个问题的最佳做法是什么?
编辑:肯定有一些 GNU 功能可以为我做这件事,并且已经使用、测试和验证了 20 年?
我目前正在研究一些任意值的二进制文件格式,包括一些字符串和字符串长度值,它们存储为uint32_t
's.
但我想知道,如果我将字符串长度写入fwrite
小端系统上的文件,并在大端系统上从同一个文件中读取该值,fread
字节的顺序会反转吗?如果是这样,解决这个问题的最佳做法是什么?
编辑:肯定有一些 GNU 功能可以为我做这件事,并且已经使用、测试和验证了 20 年?
是的,fwrite
并且fread
在整数上使您的文件格式无法移植到另一个字节序,正如其他答案正确说明的那样。
作为最佳实践,我完全不鼓励任何有条件的字节翻转和字节序测试。确定文件格式的字节顺序,而不是写入和读取字节,并通过 ORing 和移位从它们中生成整数。
换句话说,我同意 Rob Pike在这个问题上的看法。
如果我使用 fwrite 将字符串长度写入 little-endian 系统上的文件,并在 big-endian 系统上使用 fread 从同一个文件中读取该值,字节的顺序是否会反转?
是的。 fwrite
简单地将内存内容以线性顺序写入文件。 fread
只是以线性顺序从文件读取到内存。
解决这个问题的最佳做法是什么?
决定您的文件的顺序。然后编写包装函数来向/从文件中写入和读取整数。在此函数中,如果您在具有相反顺序的系统上,则有条件地翻转字节顺序。
(这里有很多关于确定系统字节序的问题。)
当然必须有一些 GNU 功能来为我做这件事
标准库中什么都没有。但是,POSIX 为此定义了一堆函数:ntohl
、htonl
等。它们通常用于网络传输,但同样可以用于文件。
是的,它会,因为fread()
对战争原始字节进行操作。如果内存中的字节顺序不同,文件中的字节顺序也会不同。
如果是这样,解决这个问题的最佳做法是什么?
检测系统的字节序,如果它与文件格式的字节序不匹配,则翻转字节。
int is_little_endian()
{
uint32_t magic = 0x00000001;
uint8_t black_magic = *(uint8_t *)&magic;
return black_magic;
}
uint32_t to_little_endian(uint32_t dword)
{
if (is_little_endian()) return dword;
return (((dword >> 0) & 0xff) << 24)
| (((dword >> 8) & 0xff) << 16)
| (((dword >> 16) & 0xff) << 8)
| (((dword >> 24) & 0xff) << 0);
}
Linux 提供
htobe16, htole16, be16toh, le16toh, htobe32, htole32, be32toh, le32toh, htobe64, htole64, be64toh, le64toh - 在主机和大/小端字节顺序之间转换值