c++ - 读取由结构定义的二进制文件

标签 c++ data-structures binary

有人能指出我如何读取由 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]
}

如果有人能为我指明正确的方向,我将不胜感激。或者是否有任何涵盖该主题的教程?

非常感谢您的帮助。

最佳答案

有一些坏点子和好点子:

这是个坏主意:

  • 将原始缓冲区类型转换为结构
    • endianness解析整数 >1 字节长或 float 时的问题(小端与大端)
    • byte alignment issues在非常依赖编译器的结构中。可以尝试禁用对齐(或强制执行一些手动对齐),但这通常也是一个坏主意。至少,让 CPU 访问未对齐的整数会破坏性能。内部 RISC 核心必须执行 3-4 次操作而不是 1 次(即“在第一个字中执行第 1 部分”、“在第二个字中执行第 2 部分”、“合并结果”)才能每次访问它。或者更糟的是,控制对齐的编译器编译指示将被忽略,您的代码将中断。
    • 对于常规 intlongshort 等 C/C++ 类型,没有精确的大小保证。您可以使用 int16_t 之类的东西,但这些只能在现代编译器上使用。
    • 当然,当使用引用其他结构的结构时,这种方法会完全失效:必须手动展开它们。
  • 手动编写解析器:这比乍看起来要难得多。
    • 一个好的解析器需要在每个阶段做大量的健全性检查。很容易错过一些东西。如果不使用异常,就更容易错过一些东西。
    • 如果您的解析代码不是异常安全的(即以一种可以在某些点中断并且不会泄漏内存/忘记完成某些对象的方式编写),使用异常会使您容易失败
    • 可能存在性能问题(即执行大量无缓冲的 IO 而不是执行一个操作系统 read 系统调用然后解析缓冲区 — 反之亦然,一次读取整个内容而不是更细粒度,懒惰在适用的地方阅读)。

这是个好主意

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

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

  • Kaitai Struct — 目前为止我最喜欢的,跨平台、跨语言 — 也就是说,您只需描述一次结构,然后就可以将其编译成 C++、C#、Java、Python、Ruby、PHP 等语言的解析器。
  • binpac — 相当过时,但仍然可用,仅限 C++ — 在意识形态上类似于 Kaitai,但自 2013 年以来不受支持
  • Spicy — 据说是 binpac 的“现代重写”,又名“binpac++”,但仍处于开发的早期阶段;可以用于较小的任务,也只能用于 C++。

关于c++ - 读取由结构定义的二进制文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/868530/

相关文章:

c++ - 我的程序可以在我的电脑上运行,但不能在 CodeEval 上运行

c++ - 使用 ycbcr 格式捕获相机图像

c++ - std::array 大小在类包装器实例化时设置

c++ - 函数重载的类模板声明

c++ - 为什么使用 clock() 在测量 CPU 时间时得到负数

algorithm - Quick sort中三分区的Median是如何提高5%左右效率的?

algorithm - 给定一个数字 p ,在数组中找到两个乘积 = P 的元素

c# - 我怎样才能处理一个对象

c - 如何在 C 中将纪元十进制时间转换为 64 位二进制并返回十进制

binary - 为什么我们不使用 base64 而不是十六进制?