将文件内容加载到 C++ 结构中

Load file contents into a C++ struct

我有一个 ASCII 文件,看起来像这样(文件很大,所以只粘贴部分内容):

ffffffffffffffff0064000a000a000c
02000000000000000b0000111f0a0503
00000000000002000000000000000000
00000000000000000000000000000000
02000000000000000000020400000000
00000000000000000000000000000000
00000000000000000000000000000000
ffffffffffffffffffffffff00000000
ffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffff

我有一个看起来像这样的结构:

typedef struct frame {

  uint16_t kps;
  uint16_t num_h_region;
  uint16_t num_v_region;
  uint16_t num_r;
  uint8_t reserved1[7];
  uint8_t kp_per_region[100];
  uint8_t reserved[397];

  kp_info_t kp_info[2000];
  uint32_t desc[2000];

} frame_t;

其中:

typedef struct kp_info {
  uint32_t subpixel_idx_x;
  uint32_t subpixel_idx_y;
  uint32_t orientation;
  uint32_t laplacian;
  uint8_t scale;
  uint8_t minima; // 1 bit
  uint8_t dmy1[14];
  uint32_t subpixel_match0_x;
  uint32_t subpixel_match0_y;
  uint32_t subpixel_match1_x;
  uint32_t subpixel_match1_y;
  uint32_t distance_match0;
  uint32_t distance_match1;
  uint8_t ambiguous; // 1 bit
  uint8_t dmy2[7];
} kp_info_t;

输入文件应该像这样分配给 frame_t 结构成员:

frame_t fr;
fr.kps = 0x000c;
fr.num_h = 0x000a;
fr.num_v = 0x000a;
fr.num_r = 0x0064;
fr.reserved1[0] = 0xff;
fr.reserved1[1] = 0xff;
fr.reserved1[2] = 0xff;
fr.reserved1[3] = 0xff;
fr.reserved1[4] = 0xff;
fr.reserved1[5] = 0xff;
fr.reserved1[6] = 0xff;
fr.reserved1[7] = 0xff;
fr.kps_per_region[0] = 0x03;
fr.kps_per_region[1] = 0x05;
fr.kps_per_region[2] = 0x0a;
fr.kps_per_region[3] = 0x1f;
fr.kps_per_region[4] = 0x11;
fr.kps_per_region[5] = 0x00;
fr.kps_per_region[6] = 0x00;
fr.kps_per_region[7] = 0x0b;
fr.kps_per_region[8] = 0x00;
fr.kps_per_region[9] = 0x00;
fr.kps_per_region[10] = 0x00;
fr.kps_per_region[11] = 0x00;
fr.kps_per_region[12] = 0x00;
fr.kps_per_region[13] = 0x00;
fr.kps_per_region[14] = 0x00;
fr.kps_per_region[15] = 0x02;
.. so on.

我已经将 ASCII 文件转换为二进制文件,但我不知道如何正确地进行赋值。我正在努力处理排序,以及在(不同的)结构中使用结构数组。

二进制文件如下所示:

00000000: ffff ffff ffff ffff 0064 000a 000a 000c  .........d......
00000010: 0200 0000 0000 0000 0b00 0011 1f0a 0503  ................
00000020: 0000 0000 0000 0200 0000 0000 0000 0000  ................
00000030: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000040: 0200 0000 0000 0000 0000 0204 0000 0000  ................
00000050: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000060: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000070: ffff ffff ffff ffff ffff ffff 0000 0000  ................
00000080: ffff ffff ffff ffff ffff ffff ffff ffff  ................
00000090: ffff ffff ffff ffff ffff ffff ffff ffff  ................
000000a0: ffff ffff ffff ffff ffff ffff ffff ffff  ................
000000b0: ffff ffff ffff ffff ffff ffff ffff ffff  ................
000000c0: ffff ffff ffff ffff ffff ffff ffff ffff  ................
000000d0: ffff ffff ffff ffff ffff ffff ffff ffff  ................

这是我的尝试:

union u_frame {
  char mem[sizeof(frame_t)];
  frame_t fr;
} uf;


void load_text_file(frame_t& f, const std::string& s)
{
  std::fstream input;
  input.open(s, std::fstream::in | std::fstream::binary);
  if(!input.is_open())
  {
    fprintf(stderr, "\nError opening file\n");
    exit(1); 
  }

  std::cout << "Size of frame_t = " << std::hex << sizeof(frame) << std::endl;
  std::cout << "File opened successfully\n";

  input.read(uf.mem, sizeof(frame_t));

  std::cout << "total_kps = " << uf.fr.total_kps
            << "\nnum_h_region = " << uf.fr.num_h_region
            << "\nnum_v_region = " << uf.fr.num_v_region
            << "\nnum_region = " << uf.fr.num_region;

  for(size_t i = 0; i < 8; ++i)
    std::cout << "\nreserved[" << i << "] = " << std::hex << (std::uint32_t)(uf.fr.reserved1[i]);

  // Printing the first 15 kp_per_region
  for(size_t i = 0; i < 15; ++i)
  {
    std::cout << "\nkps_per_region[" << i << "] = " << (std::uint32_t)(uf.fr.kp_per_region[i]); 
  }
}

int main() {

  frame_t left;

  std::cout << "Loading left frame -- \n";

  load_text_file(left, "line_ddr.bin");

  return 0;
}

这是输出:

Loading left frame -- 
Size of frame_t = 119600
File opened successfully
total_kps = ffff
num_h_region = ffff
num_v_region = ffff
num_region = ffff
reserved[0] = 0
reserved[1] = 64
reserved[2] = 0
reserved[3] = a
reserved[4] = 0
reserved[5] = a
reserved[6] = 0
reserved[7] = c
kps_per_region[0] = c
kps_per_region[1] = 2
kps_per_region[2] = 0
kps_per_region[3] = 0
kps_per_region[4] = 0
kps_per_region[5] = 0
kps_per_region[6] = 0
kps_per_region[7] = 0
kps_per_region[8] = 0
kps_per_region[9] = b
kps_per_region[a] = 0
kps_per_region[b] = 0
kps_per_region[c] = 11
kps_per_region[d] = 1f
kps_per_region[e] = a

如果需要其他信息,请告诉我(特别是因为我只粘贴了输入文件的一部分)。

您的代码完全按照您指定的方式执行。采用 input 流并将 sizeof(frame_t) 字节加载到您的 uf 中。需要注意的一件事是,您的 file/stream 是从“左到右”、“逐字节”读取的,因此您将从 [=14= 加载的前两个字节(因为您指定了 uint16_t) ] 到 frame_t.kps 将是 ffff 而不是 000c。进一步调查的好方法是设置几个断点并逐步调试代码。您将学习重要的调试技术并了解有关代码工作原理的更多信息。

顺便说一句,我很惊讶你没有明白 stack overflow exception。该结构 巨大 .

没有深入了解填充的工作原理和应用程序限制等太多细节 - 这对理解非常有用,但不是解决此类问题所必需的,我很乐意支持不同的方法。

我们这里有两个主要问题要解决:

  1. 我们正在序列化和反序列化数据
  2. 我们有一个大文件,其中存在此​​类数据(或者我们想写入它)

因此我们应该问 2 个问题:

  1. 我们如何序列化和反序列化数据?
  2. 这种序列化和反序列化数据的方式是否可以在文件中作为二进制流工作?

作为第一个问题的答案,我想到的第一个库是 Messagepack Now I need to answer the second one, and indeed documentation says it should be possible: Message pack memory management

这是一个处理文件前 32 个字节的 Kaitai 结构模式,您可以在 Kaitai web IDE:

中查看它
meta:
  id: frame_t
  file-extension: frame_t
  endian: be
seq:
  - size: 8
  - id: num_r
    type: u2
  - id: num_h_region
    type: u2
  - id: num_v_region
    type: u2
  - id: kps
    type: u2
  - id: kp_per_region
    type: u1
    repeat: expr
    repeat-expr: 16

很遗憾,我无法帮助您编写其余部分,因为我不清楚文件的其余部分如何映射到您显示的结构。