我目前正在为一些任意值开发二进制文件格式,包括一些字符串和字符串长度值,这些值存储为uint32_t
的s。
但我想知道,如果我用fwrite
将字符串长度写入小端系统上的文件,并从大端系统上用fread
的同一文件中读取该值,字节的顺序会颠倒吗?如果是这样的话,解决这个问题的最佳做法是什么?
编辑:肯定有一些GNU功能可以为我做到这一点,并且使用、测试和验证了大约20年?
是的,整数上的fwrite
和fread
会使您的文件格式无法移植到另一个字节序,正如其他答案正确指出的那样。
作为最佳实践,我会完全不鼓励任何条件字节翻转和端序测试。决定文件格式的字节序,而不是写入和读取字节,并通过OR和移位从中生成整数。
换句话说,在这个问题上,我同意Rob Pike的观点。
如果我用fwrite将字符串长度写入小端系统上的文件,并在大端系统上用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
[https://linux.die.net/man/3/le32toh]