字节序是否会影响写入奇数字节

Does endianness affect writing an odd number of bytes?

本文关键字:字节 数字 影响 是否      更新时间:2023-10-16

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

在编写文件时,您可以执行类似的操作

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

仅写入7个字节。

我想弄清楚的问题是,系统的端序是否会影响写入文件的字节数。我知道端序会影响字节的写入顺序,但它也会影响写入的字节吗?(仅适用于写入的字节数少于整数通常的字节数的情况。)

例如,在little-endian系统上,前7个字节从LSB开始写入文件。在big-endian系统中,文件中写入了什么?

换句话说,在小端序系统中,MSB(第8个字节)不会写入文件。在big-endian系统上,我们能期待同样的行为吗?

Endianess只影响(16,32,64)int的写入方式。如果您正在写入字节,(根据您的情况)它们将以与您执行操作完全相同的顺序写入。

例如,这种书写会受到endianes:的影响

std::ofstream fout(fileName);
int i = 67;
fout.write((char *)&i, sizeof(int));
uint64_t bytes = ...;
fout.write((char *)&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在回答中所做的那样。为了避免多个系统调用,您可以将值分解为一个数组并打印出该数组。

如果在linux/BSD上,也有一个不错的替代方案:

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

我想弄清楚的问题是系统的端序是否会影响写入文件的字节。

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

例如,在little-endian系统上,前7个字节从LSB开始写入文件。在big-endian系统中,文件中写入了什么?

前7个字节写入文件。但这一次,从MSB开始。因此,最后,最低的字节是而不是写入文件中,因为在big-endian系统中,最后一个字节是最低的字节。

所以,这不是你想要的,因为你失去了信息。

一个简单的解决方案是将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