使用 c/c++ 解析二进制文件

Parsing binary files using c/c++

本文关键字:二进制文件 c++ 使用      更新时间:2023-10-16

我目前正在处理一些二进制文件,数据格式在某些文件中指定。我使用的方法是定义一些相应的结构,以便从缓冲区中逐个读取数据。例如,如果我知道在文件的开头,有一个数据包标头指定了该数据包中的以下数据类型和数据长度,我将首先解析此数据包标头。

  #pragma pack (1)
  struct PacketHeader
  {
     uint16_t PacketSize;
     uint16_t PacketType;
  };
  char *buffer = new char[size];
  file.read(buffer, size);
  //read in the PacketHeader
  PacketHeader ph;
  ph = *(PacketHeader *)buffer;
  //switch data type
  switch(ph.PacketType)
  {
     //do something
  }

到目前为止,一切顺利,但是当我不使用结构方法时会出现问题。例如,我知道在数据类型A之后缓冲区的某个位置,会有一些关于A底层组成的信息,比如一个uint32_t变量,另一个uint32_t变量。这种变量对的数量在 A 中指定,并且由于该对中只有两个变量,我尝试直接解析它们而没有任何结构,例如,

  //get pair_num from previous parsed data
  for(int i = 0; i < pair_num; i++)
  {
      std::cout << (uint32_t)(buffer + 2 * i * sizeof(uint32_t))
                << (uint32_t)(buffer + (2 * i + 1) * sizeof(uint32_t))
                << std::endl;
  }

但是,上面的代码不起作用。从文件中解析的两个变量是错误的。所以我回到结构方法,并设法使用以下代码获得正确的结果:

 struct B
 {
    uint32_t v1;
    uint32_t v2;
 }
 B b;
 //get pair_num from previous parsed data
 for(int i = 0; i < pair_num; i++)
 {
     b = *(B *)(buffer + i * 8);
     std::cout << b.v1
               << b.v2
               << std::endl;
 }

我只是想知道这两种方法有什么区别?有人能给我一些见解吗?

不是将char *转换为uint32_t *并取消引用它,而是char *将指针转换为uint32_t以便在std::cout上打印地址(或 64 位机器上的一部分地址(,正确的方法应该是这样的:

  for(int i = 0; i < pair_num; i++)
  {
      std::cout << *((uint32_t *)(buffer + 2 * i * sizeof(uint32_t)))
                << *((uint32_t *)(buffer + (2 * i + 1) * sizeof(uint32_t)))
                << std::endl;
  }

但更简单的方法是使用适当的指针:

  uint32_t *ptr = (uint32_t *) buffer;
  for(int i = 0; i < pair_num; i++)
  {
      std::cout << *(ptr + 2 * i )
                << *(ptr + 2 * i + 1 )
                << std::endl;
  }

甚至:

  uint32_t *ptr = (uint32_t *) buffer;
  for(int i = 0; i < pair_num; i++)
  {
      std::cout << ptr[2 * i]
                << ptr[2 * i + 1]
                << std::endl;
  }

请注意,在第二种方式(以及使用标题作为结构(中,您正在执行不必要的复制,我认为您想要的是:

struct B
 {
    uint32_t v1;
    uint32_t v2;
 }
 //get pair_num from previous parsed data
 for(int i = 0; i < pair_num; i++)
 {
     B *b = (B *)(buffer + i * 8);
     std::cout << b->v1
               << b->v2
               << std::endl;
 }

除非您出于某种原因有意复制该结构。