【问题标题】:Best way read and compare byte data from binary files in C++?从 C++ 中的二进制文件读取和比较字节数据的最佳方法?
【发布时间】:2015-12-15 18:59:02
【问题描述】:

我不知道如何使用 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 字符完全不相关的其他文件的。 例如,每个以 0xCAFEBABE 开头的 Java 类文件都很神奇,但是当我将其读取为 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 类)的大量不同类型值的最佳方法是什么?

【问题讨论】:

  • 首先,不要使用char,因为它可能是signed其他。使用uint8_t,这是一个无符号的 8 位数量。您可以将其转换为 read() 参数内的 char 类型:in.read((char *) magic, 4);
  • 嗯?什么编译器警告?哪条线?
  • @Barry 我收到一个警告:std::array&lt;char, 4&gt; magic; inClass.read(magic.data(), 4); std::array&lt;char, 4&gt; classMagic = { 0xCA, 0xFE, 0xBA, 0xBE }; 警告:在 { } [-Wnarrowing] std::array classMagic = { 0xCA, 0xFE, 0xBA, 0xBE }; ^
  • @user3530525:左边没有填充。在这种情况下,char 似乎是有符号的,因此每个大于 0x7F (=127) 的值都会溢出为负值。当将负值转换为 int 时,它应该保持负数,因此您可以将它们读取为例如 0xffffffca,它与 char 0xca,-56 具有相同的值。

标签: c++ parsing io byte


【解决方案1】:

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

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

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

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

【讨论】:

  • 谢谢。有没有办法避免必须设置常数值进行比较?我有点想避免大量声明我需要比较的值。另外,你能看看我的更新吗?
  • @user3530525 好吧,您想与常量值进行比较。你还会怎么做呢?并且不要在问题上添加问题——尤其是完全不相关的问题。
  • 有没有办法“内联”声明 std::arrays?所以我可以把它放在一个if语句评估中吗?所以,我基本上是在其中匿名声明它,而不是将它作为常量放在其他地方,因为我只会比较魔法一次。
  • 您不必进行显式转换。最好使用字符常量:std::array&lt;char, 2&gt; shoudlBe { '\x4d', '\x5a'};
【解决方案2】:

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

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),然后从文件中的正确字节数创建一个字符串,然后与预期值进行比较。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-08
    • 2019-04-04
    • 1970-01-01
    • 2017-02-07
    相关资源
    最近更新 更多