从 C++ 中的二进制文件读取和比较字节数据的最佳方法?

Best way read and compare byte data from binary files in C++?

我不知道如何使用 char 数组(std::ifstream.read() 的第一个参数来比较不同类型的数据)。

例如,如果我试图阅读 Windows PE 文件的魔力,我正在这样做,但我觉得有更好的方法,因为据我所知,这需要我定义每个文件中的预设值为 std::array:

std::array<char, 2> magic;
in.read(magic.data(), magic.size());
std::array<char, 2> shouldBe = { 0x4d, 0x5a }; // MZ for dos header

if(magic == shouldBe) {
    // magic correct
}

这给了我编译器警告,例如从 int 到 char 的无效转换。 我也不太明白我是如何阅读十六进制值与 ASCII 字符完全不相关的其他文件的魔法。 例如,每个 Java class 文件都以 0xCAFEBABE 开头是一个魔法,但是当我将它读入 4 个字符然后将每个部分转换为一个 int 时,我得到了我不想要的填充离开了。

char* magic = new char[4];
in.read(magic, 4);
// how can I compare this array to 0xCAFEBABE?

当我遍历每个部分然后转换为 int 并在输出流中使用 std::hex 时的输出:

ffffffca fffffffe ffffffba ffffffbe

解析 PE 文件和 Java classes 等二进制文件格式中使用的大量不同类型值的最佳方法是什么?

这个方法非常好。唯一的问题是这一行:

std::array<char, 2> shouldBe = { 0x4d, 0x5a }; // MZ for dos header

列表初始化不允许缩小转换,因此您只需要进行一些显式转换:

std::array<char, 2> shouldBe = { (char)0x4d, (char)0x5a };

您基本上有两种选择:可以将值硬编码到程序中,也可以将它们存储在外部。如果您将它们存储在内部,最简单的方法可能是从对数据进行一些结构化开始:

struct magic { 
    std::string value;
    int result;
};

std::vector<magic> values { 
    { ".ELF", 1 },
    { "MZ", 2},
    { "\xca\xfe\xba\xbe", 3}, // 0xcafebabe
    { "etc", -1}};

然后您可以(例如)在循环中单步执行值,比较值,当您获得匹配时有一个值告诉您(例如)如何处理那种文件。

如果像我在此处所做的那样将值存储为字符串,那么将比较也作为字符串进行可能最简单。一种明显的方法是从文件开头读入一个块(例如 2 KB),然后根据文件中正确的字节数创建一个字符串,然后与预期值进行比较。