假设您有一个uint64_t bytes
,并且您知道只需要7个字节,因为存储的整数不会超过7个字节的限制。
在编写文件时,您可以执行以下操作
std::ofstream fout(fileName); fout.write((char *)&bytes, 7);
只写7个字节。
我想弄清楚的问题是,系统的安全性是否会影响写入文件的字节。我知道endianess会影响字节的写入顺序,但它是否也会影响写入的字节呢?(只适用于写入字节比整数通常少的情况。)
例如,在一个小的endian系统上,头7个字节被写入文件,从LSB开始。在大终端系统中,什么是写入文件的?
或者换句话说,在一个小的endian系统上,MSB(第8字节)没有写入文件。我们能期望在一个大终端系统上出现同样的行为吗?
发布于 2019-01-08 12:10:26
uint64_t bytes = ...;
fout.write((char *)&bytes, 7);
这将准确地写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-System编写的数据在回读时会被LE-system误解,反之亦然。安全版本将像盖萨在其回答中所做的那样,对每个字节进行分解。为了避免多个系统调用,您可以将值分解为一个数组,然后打印出来。
如果在linux/BSD上,也有一个不错的替代方案:
bytes = htole64(bytes); // will likely result in a no-op on LE system...
fout.write((char *)&bytes, 7);
发布于 2019-01-08 11:51:13
恩典只影响(16,32,64) int
的书写方式。如果您正在编写字节(这是您的情况),它们将按照与您所做的完全相同的顺序编写。
例如,这种写作方式会受到以下因素的影响:
std::ofstream fout(fileName);
int i = 67;
fout.write((char *)&i, sizeof(int));
发布于 2019-01-08 12:12:04
我想弄清楚的问题是,系统的安全性是否会影响写入文件的字节。
是的,它会影响到写入文件的字节。
例如,在一个小的endian系统上,头7个字节被写入文件,从LSB开始。在大终端系统中,什么是写入文件的?
前7个字节被写入文件。但这一次从MSB开始。所以,最后,最低的字节是而不是写入文件,因为在大终端系统中,最后一个字节是最低字节。
所以,这不是你想要的,因为你失去了信息。
一个简单的解决方案是将uint64_t
转换为小endian,并编写转换后的值。或者用一种小的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
https://stackoverflow.com/questions/54091194
复制相似问题