字节序是否影响写入奇数个字节?

Does endianness affect writing an odd number of bytes?

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

写文件时你可以做类似的事情

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

只写 7 个字节。

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

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

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

字节序仅影响 (16, 32, 64) int 的书写方式。如果您正在编写 bytes,(根据您的情况)它们将按照您正在执行的完全相同的顺序编写。

比如这种写法会受到endianess的影响:

std::ofstream fout(fileName);
int i = 67;
fout.write((char *)&i, sizeof(int));
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)]

起始地址 (0xff00) 如果转换为 char* 则不会改变,并且您将打印出恰好位于该地址的字节加上接下来的六个字节 - 在这两种情况下(LE 和 BE ), 地址 0xff07 将不会被打印出来。现在如果你看看我上面的记忆table,很明显在BE系统上,你在存储不携带信息的MSB时丢失了LSB...

在 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 did in his 。为避免多次系统调用,您可以将值分解为一个数组并打印出该数组。

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

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

The question I'm trying to figure out is whether endianess of a system affects the bytes that are written to the file.

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

For example, on a little endian system the first 7 bytes are written to the file, starting with the LSB. On a big endian system what is written to the file?

前 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