使用C ++读取二进制文件会返回意外值

时间:2019-07-06 04:13:11

标签: c++ binary

我是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 ++应该如何工作缺乏了解?

1 个答案:

答案 0 :(得分:3)

这是一个字节序问题。文件中的数据以大端顺序存储,但是您的CPU使用小端顺序。

5010x01F5十六进制表示。 -28150xF501十六进制表示(假设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”标头中可以找到。