有人能指出我如何读取由 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 部分”、“合并结果”)才能每次访问它。或者更糟的是,控制对齐的编译器编译指示将被忽略,您的代码将中断。
- 对于常规
int
、long
、short
等 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/