【问题标题】:How do you convert a C data structure to a C# struct that will allow you to read the data type from a file?如何将 C 数据结构转换为允许您从文件中读取数据类型的 C# 结构?
【发布时间】:2013-12-16 02:21:27
【问题描述】:

我有一个二进制文件,它是由一个用 C 语言编写的开源应用程序创建的。由于它是开源的,因此我可以看到数据在写入文件时的结构。问题是我不懂 C,但我至少可以大致了解在声明结构时发生了什么。但从我在其他帖子中看到的情况来看,这并不像在 C# 中创建一个与 C 中的数据类型相同的结构那么简单。

我发现这篇帖子https://stackoverflow.com/a/3863658/201021 有一个用于翻译结构的类,但是(据我所知)您需要在 C# 中正确声明该结构才能使其工作。

我读过MarshalAs attributeStructLayout attribute。我主要了解您将如何使用它们来控制数据类型的物理结构。我认为我缺少的是细节。

我并不是要求某人将 C 数据结构转换为 C#。我真正想要的是一些指向信息的指针,这些信息将帮助我自己弄清楚如何去做。我有另一个格式稍有不同的二进制文件可供阅读,因此非常感谢您了解有关此主题的一般知识。

如何将 C 数据结构转换为允许您从文件中读取数据类型的 C# 结构?

注意事项: 具体来说,我正在尝试读取 Tomato 路由器固件输出的 rstats 和 cstats 文件。此文件包含带宽使用数据和 ip 流量数据。

数据结构的C代码是(来自rstats.c):

#define MAX_COUNTER 2
#define MAX_NSPEED      ((24 * SHOUR) / INTERVAL)
#define MAX_NDAILY      62
#define MAX_NMONTHLY    25

typedef struct {
    uint32_t xtime;
    uint64_t counter[MAX_COUNTER];
} data_t;

typedef struct {
    uint32_t id;

    data_t daily[MAX_NDAILY];
    int dailyp;

    data_t monthly[MAX_NMONTHLY];
    int monthlyp;
} history_t;

typedef struct {
    char ifname[12];
    long utime;
    unsigned long speed[MAX_NSPEED][MAX_COUNTER];
    unsigned long last[MAX_COUNTER];
    int tail;
    char sync;
} speed_t;

【问题讨论】:

  • 将 struct 从 C 转换为 C# 的一种更简单的方法是,您可以使用 thrift 或 avro 等语言独立的序列化库,并在它们之间转换数据。

标签: c# c data-structures


【解决方案1】:

我认为您的第一个链接https://stackoverflow.com/a/3863658/201021 是一个很好的关注方式。所以我猜接下来会构建一个 C# 结构来映射 C 结构。这是来自 MSDN http://msdn.microsoft.com/en-us/library/ac7ay120(v=vs.110).aspx的不同类型的地图

干杯!

【讨论】:

    【解决方案2】:

    我也不是 ANSI C 程序员,但乍一看源文件,它似乎是将数据保存到 .gz 文件中,然后重命名它。 open 函数用 gzip 解压它。因此,您可能正在查看顶层的压缩文件。

    一旦你知道你正在处理原始文件,看起来最好的起点是load(int new) 函数。您需要弄清楚如何对正在发生的事情进行逆向工程。如果您迷路了,您可能需要了解一些本机 C 函数调用的工作原理。

    第一个有趣的行是:

    if (f_read("/var/lib/misc/rstats-stime", &save_utime, sizeof(save_utime)) != sizeof(save_utime)) {
             save_utime = 0;
    }
    

    在扫描文件时,save_time 被声明为 long。在 C 中,这是一个 32 位数字,因此 int 是 C# 等价物。鉴于它的名称,它似乎是一个时间戳。所以,第一步似乎是读入一个 4 字节的 int。

    下一个有趣的部分是

    speed_count = decomp(hgz, speed, sizeof(speed[0]), MAX_SPEED_IF);
    

    save 函数中,它将speed 保存为具有sizeof() * count 类型行为的size_t 结构数组。但是,它不是save 的实际计数。由于它将MAX_SPEED_IF(定义为= 10)从load 函数传递到decomp,因此查看它在decomp 中的作用是有意义的。看起来,它似乎试图read( ... size * max)(又名size * MAX_SPEED_IF)并依赖read库函数的返回值来了解实际保存了多少size_t结构。

    从那里,只需为写入的 size_t 结构数读取正确的字节数即可。然后,它继续加载历史数据。

    这是我能想到的在引用源代码并将其同时移植到不同语言的同时对二进制文件进行逆向工程的唯一方法。

    顺便说一句。我只是提供我的帮助。我可能完全错了。就像我说的,我不是 ansi c 人。但是,我确实希望这有助于您继续前进。

    【讨论】:

      【解决方案3】:

      简短的回答是,您可能无法自动执行此操作,至少在运行时是这样。 知道编写了多少 C 程序,文件中几乎没有任何元数据的机会。即使有,您也需要将其称为“使用这种格式的元数据读取数据的程序”。还有各种细微之处,比如字长、打包等。

      恐怕仅仅因为这两种语言的名称中有“C”并不能使它们神奇地兼容。我担心你需要为每种文件类型编写一个特定的程序,作为其中的一部分,在 C# 中重新声明你的结构

      【讨论】:

      • 他有结构的来源。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-06
      • 2016-09-10
      • 1970-01-01
      相关资源
      最近更新 更多