字节顺序会影响写入奇数个字节吗?

时间:2019-01-08 11:47:57

标签: c++ file-io endianness

假设您有一个uint64_t bytes,并且知道只需要7个字节,因为存储的整数不会超过7个字节的限制。

编写文件时,您可以做类似的事情

std::ofstream fout(fileName); fout.write((char *)&bytes, 7);

只写7个字节。

我要解决的问题是系统的耐久性是否会影响写入文件的字节。我知道字节序会影响写入字节的顺序,但是还会影响写入哪些字节吗? (仅适用于您写入的字节数少于通常的整数的情况。)

例如,在小端系统上,前7个字节从LSB开始写入文件。在大型字节序系统上,文件中写入了什么?

或者换句话说,在小端系统上,MSB(第8个字节)未写入文件。在大型字节序系统上,我们可以期待相同的行为吗?

3 个答案:

答案 0 :(得分:2)

字节序仅影响({16,32,64)int的写入方式。如果您要写入 bytes (根据实际情况),它们的写入顺序将与您执行的完全相同。

例如,这种文字会受到字节顺序的影响:

std::ofstream fout(fileName);
int i = 67;
fout.write((char *)&i, sizeof(int));

答案 1 :(得分:1)

uint64_t bytes = ...;
fout.write((char *)&bytes, 7);

这将从地址&bytes开始精确地写入7个字节。 LE和BE系统之间的区别在于,如何对存储器中的八个字节进行布局(假设变量位于地址0xff00上)

            0xff00  0xff01  0xff02  0xff03  0xff04  0xff05  0xff06  0xff07
LE: [byte 0 (LSB!)][byte 1][byte 2][byte 3][byte 4][byte 5][byte 6][byte 7 (MSB)]
BE: [byte 7 (MSB!)][byte 6][byte 5][byte 4][byte 3][byte 2][byte 1][byte 0 (LSB)]

如果将其强制转换为char *,则起始地址(0xff00)不会改变,并且您将在此地址正好打印出字节,再输出随后的六个字节–在两种情况下(LE和BE),地址0xff07将不会打印。现在,如果您看一下上面的内存表,显然在BE系统上,您在存储MSB时会丢失LSB,而MSB不会携带信息...

在BE系统上,您可以改写fout.write((char *)&bytes + 1, 7);。但是请注意,这仍然存在可移植性问题:

fout.write((char *)&bytes + isBE(), 7);
//                           ^ giving true/false, i. e. 1 or 0
// (such function/test existing is an assumption!)

这样,当回读时,由BE系统写入的数据将被LE系统误解,反之亦然。安全版本将按照geza在其answer中的方式分解每个字节。为了避免多次系统调用,您可以将这些值分解为一个数组,然后打印出该数组。

如果在linux / BSD上,也有一个不错的alternative

bytes = htole64(bytes); // will likely result in a no-op on LE system...
fout.write((char *)&bytes, 7);

答案 2 :(得分:1)

  

我要解决的问题是系统的耐久性是否会影响写入文件的字节。

是的,它会影响将字节写入文件。

  

例如,在小端系统上,前7个字节从LSB开始写入文件。在大型字节序系统上,文件中写入了什么?

前7个字节被写入文件。但是这次,从MSB开始。因此,最后,最低字节是 not 写在文件中的,因为在大字节序系统中,最后一个字节是最低字节。

所以,这不是您想要的,因为您会丢失信息。

一个简单的解决方案是将uint64_t转换为little endian,然后写入转换后的值。或者只是以一种字节序的方式逐个字节地写入值:

uint64_t x = ...;

write_byte(uint8_t(x));
write_byte(uint8_t(x>>8));
write_byte(uint8_t(x>>16));
// you get the idea how to write the remaining bytes