读取结构定义的二进制文件

nmu*_*ntz 3 c++ binary data-structures

有人能指出我如何读取由C结构定义的二进制文件的正确方向吗?它在结构体内部有一些#define,这使我的事情变得复杂.
结构看起来像这样:(虽然它比它更大,更复杂)

struct Format {
    unsigned long str_totalstrings;
    unsigned long str_name;
    #define STR_ORDERED 0x2
    #define STR_ROT13 0x4
    unsigned char stuff[4];
    #define str_delimiter stuff[0]
}
Run Code Online (Sandbox Code Playgroud)

如果有人能指出我如何做到这一点的正确方向,我将非常感激.或者如果那里有任何涵盖这个主题的教程?

非常感谢您的帮助.

dpm*_*min 5

有一些不好的想法和好主意:

这是一个坏主意:

  • Typecast结构的原始缓冲区
    • 解析整数> 1个字节长或浮点数时存在字节序问题(little-endian vs big-endian)
    • 结构中存在字节对齐问题,这些问题与编译器有关.可以尝试禁用对齐(或强制执行一些手动对齐),但这通常也是一个坏主意.至少,你会通过使CPU访问未对齐的整数来破坏性能.内部RISC核心必须执行3-4次操作而不是1次(即"在第一个单词中执行第1部分","在第二个单词中执行第2部分","合并结果")以便每次都访问它.或者更糟糕的是,控制对齐的编译器编译指示将被忽略,您的代码将会中断.
    • 有没有精确的尺寸保证定期int,long,short,等等,输入C/C++.您可以使用类似的东西int16_t,但这些只适用于现代编译器.
    • 当然,当使用引用其他结构的结构时,这种方法完全破坏:必须手动将它们全部展开.
  • 手动编写解析器:它比第一眼看上去困难得多.
    • 一个好的解析器需要在每个阶段进行大量的健全性检查.很容易错过一些东西.如果不使用异常,则更容易错过.
    • 如果您的解析代码不是异常安全的(例如,它可以在某些点被中断并且不会泄漏内存/忘记最终确定某些对象),则使用异常会使您容易失败
    • 可能存在性能问题(即执行大量无缓冲的IO而不是执行一个OS read系统调用然后解析缓冲区 - 反之亦然,一次读取整个内容而不是更适合的细粒度,懒惰读取).

这是一个好主意

  • 跨平台.几乎不言自明,近年来所有的移动设备,路由器和物联网都在蓬勃发展.
  • 去声明.考虑使用任何声明性规范来描述您的结构,然后使用解析器生成器来生成解析器.

有几种工具可以做到这一点:

  • Kaitai Struct - 迄今为止我最喜欢的跨平台跨语言 - 即您只需描述一次结构,然后就可以将其编译成C++,C#,Java,Python,Ruby,PHP等解析器.
  • binpac - 相当陈旧但仍然可用,仅限C++ - 与意识形态中的Kaitai相似,但自2013年以来未得到支持
  • - 据说是"现代改写"的binpac,AKA"binpac ++",但仍处于早期发展阶段; 可以用于较小的任务,C++也是如此.