假设您有一个uint64_t bytes
,并且知道只需要7个字节,因为存储的整数不会超过7个字节的限制。
编写文件时,您可以做类似的事情
std::ofstream fout(fileName);
fout.write((char *)&bytes, 7);
只写7个字节。
我要解决的问题是系统的耐久性是否会影响写入文件的字节。我知道字节序会影响写入字节的顺序,但是还会影响写入哪些字节吗? (仅适用于您写入的字节数少于通常的整数的情况。)
例如,在小端系统上,前7个字节从LSB开始写入文件。在大型字节序系统上,文件中写入了什么?
或者换句话说,在小端系统上,MSB(第8个字节)未写入文件。在大型字节序系统上,我们可以期待相同的行为吗?
答案 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