我是C ++的新手,正在阅读二进制文件。我正在尝试读取一个二进制文件,该文件的前两个字节为uint16数字。我已经编写了以下代码来读取文件。
std::ifstream large;
std::string file_path = "C:\\Users\\stewart\\Desktop\\WIN95\\WIN95\\SC2K\\DATA\\LARGE.DAT";
large.open(file_path, std::ios::binary);
large.seekg(0, std::ios::beg);
short file_entries = 0;
large.read((char*)&file_entries, sizeof(short));
在上面的代码中,file_entries是-2815
。这不是我所期望的。我希望将此值设置为501
。我在节点上写了一个JS版本来确认这一点。请注意,两个程序都读取相同的文件并返回不同的值。
function toArrayBuffer(buf) {
var ab = new ArrayBuffer(buf.length);
var view = new Uint8Array(ab);
for (var i = 0; i < buf.length; ++i) {
view[i] = buf[i];
}
return ab;
}
const fs = require('fs');
const path = "C:\\Users\\stewart\\Desktop\\WIN95\\WIN95\\SC2K\\DATA\\LARGE.DAT";
const fileContent = fs.readFileSync(path);
const dataView = new DataView(toArrayBuffer(fileContent));
const spriteFileEntries = dataView.getInt16(0x00);
为什么C ++版本返回错误的值?我对C ++应该如何工作缺乏了解?
答案 0 :(得分:3)
这是一个字节序问题。文件中的数据以大端顺序存储,但是您的CPU使用小端顺序。
501
以0x01F5
十六进制表示。 -2815
以0xF501
十六进制表示(假设16位二进制补码)。请注意,它们是相同的两个字节,只是顺序相反。
通常有两种方法来存储或传输多字节值。最高有效字节优先(AKA大字节序或网络字节顺序)或最低有效字节优先(AKA小字节序)。这两个命令非常常用,因此了解您正在读取的文件使用哪个命令很重要。大多数网络协议使用大端顺序,而大多数现代CPU使用小端顺序。
JavaScript的DataView.getInt16
假定默认情况下数据为big-endian,因为这是跨网络传输数据的常用顺序。这是有道理的,因为JavaScript通常嵌入在Web浏览器中,在Web浏览器中,通常需要与通过网络发送的数据进行交互。当将数据转换为number
时,它将自动将数据转换为适当的字节顺序。
C ++的整数类型是使用要为其编译程序的CPU的本机字节顺序存储的。当您read
进入short
时,您正在直接写入组成该short
的字节。没有完成转换。如果读取的数据顺序错误,则字节将被解释为错误的数字。
由于您要读取的数据是按网络字节顺序排列的,因此您可以使用ntohs
( n etwork h ost s hort)函数来交换字节。使用固定宽度类型而不是short
也是一个好主意,因为不能保证short
的宽度为16位:
std::string file_path = "C:\\Users\\stewart\\Desktop\\WIN95\\WIN95\\SC2K\\DATA\\LARGE.DAT";
std::ifstream large(file_path, std::ios::binary);
uint16_t file_entries;
large.read((char*)&file_entries, sizeof(file_entries));
file_entries = ntohs(file_entries);
ntohs
可以在Windows上的“ Winsock2.h”标头中找到,或者在Linux和其他兼容POSIX的操作系统上的“ arpa / inet.h”标头中可以找到。