【问题标题】:Reading Superblock into a C Structure将超级块读入 C 结构
【发布时间】:2010-12-24 06:15:33
【问题描述】:

我有一个磁盘映像,其中包含使用 fuse 的标准映像。 Superblock 包含以下内容,我有一个函数 read_superblock(*buf) 返回以下原始数据:

Bytes 0-3: Magic Number (0xC0000112)
      4-7: Block Size (1024)
     8-11: Total file system size (in blocks)
    12-15: FAT length (in blocks)
    16-19: Root Directory (block number)
  20-1023: NOT USED

我对 C 非常陌生,为了让我开始这个项目,我很好奇有什么简单的方法可以将它读入结构或一些变量,然后使用 printf 将它们打印到屏幕上进行调试。

我最初考虑做类似以下的事情,认为我可以看到原始数据,但我认为情况并非如此。也没有结构,我试图将其作为字符串读取,这似乎也非常错误。让我从中获取数据。有没有办法让我指定结构并定义每个变量中的字节数?

char *buf;
read_superblock(*buf);
printf("%s", buf);

【问题讨论】:

  • 请注意,您还需要检查这个假设的 read_superblock() 中的错误以及调用它的人...

标签: c++ c fuse


【解决方案1】:

这里要补充两点:

  1. 在将原始数据拉入结构时,最好将结构设置为零填充,即使它完全由 32 位无符号整数组成。在 gcc 中,您可以在结构定义之前使用 #pragma pack(0) 并在其之后使用 #pragma pack() 来执行此操作。
  2. 为了处理潜在的字节顺序问题,需要查看的两个调用是 ntohs()ntohl(),分别用于 16 位和 32 位值。请注意,这些从网络字节顺序交换到主机字节顺序;如果它们相同(它们不在基于 x86 的平台上),它们什么也不做。您使用htons()htonl() 从主机到网络字节顺序。但是,由于这些数据来自您的文件系统而不是网络,我不知道字节序是否是一个问题。通过将您期望的值(例如块大小)与您获得的值(以十六进制进行比较)来计算应该很容易。

【讨论】:

  • +1 用于结构填充。但是,至于第 2 点...我会确认该结构实际​​上是使用网络字节顺序。根据格式,big-endian CPU 可能是需要进行交换的 CPU。 (这在磁盘结构上很常见,假设 x86 会更常见。)
  • -1 用于结构填充,-1 用于对字节序使用非标准函数。原始海报未指定编译器,因此编译指示可能不可用。 ntohs() 和 ntohl() 不是标准函数;由于未指定编译器,再次无法具体说明。
【解决方案2】:

是的,我认为你最好把它读成一个结构。包含有用数据的字段都是 32 位整数,因此您可以定义如下所示的结构(使用标准头文件 stdint.h 中定义的类型):

typedef struct SuperBlock_Struct {
  uint32_t magic_number;
  uint32_t block_size;
  uint32_t fs_size;
  uint32_t fat_length;
  uint32_t root_dir;
} SuperBlock_t;

您可以在调用read_superblock 时将结构转换为char*,如下所示:

SuperBlock_t sb;
read_superblock((char*) &sb);

现在要打印出您的数据,您可以拨打如下电话:

printf("%d %d %d %d\n",
  sb.magic_number,
  sb.block_size,
  sb.fs_size,
  sb.fat_length,
  sb.root_dir);

请注意,在使用此类技术时,您需要注意平台的字节顺序,因为您正在读取整数数据(即,您可能需要在读取数据时交换字节)。您应该能够使用第一个字段中的幻数快速确定。

请注意,通常最好在不强制转换的情况下传递这样的结构;这使您可以利用编译器的类型检查并消除强制转换可能隐藏的潜在问题。但是,这将需要更改 read_superblock 的实现以将数据直接读取到结构中。这并不难,可以使用标准 C 运行时函数 fread 来完成(假设您的数据在文件中,如您的问题中所暗示的那样),如下所示:

fread(&sb.magic_number, sizeof(sb.magic_number), 1, fp);
fread(&sb.block_size, sizeof(sb.block_size), 1, fp);
...

【讨论】:

  • 谢谢,这很有帮助。
  • 你没有做任何事情来确保编译器不会插入填充对齐。
  • 我不能,因为我不知道原始发布者使用的是什么编译器(结构打包是相当特定于编译器的)。但是你的观点是有效的;当使用我描述的第一种方法(将结构转换为 char*)时,通常您必须打包结构以避免任何与填充相关的问题。
  • 结构是个好主意,但是,由于成员之间可能存在填充,因此必须从输入流(或缓冲区)中单独读取每个字段。没有用于打包结构的标准编译器选项。请记住:结构的大小不等于其成员大小的总和。
【解决方案3】:

将数据成功复制到 Emerick 提出的结构后,打印数据并不难。假设您用来保存数据的结构的实例名为 SuperBlock_t_Instance。

然后你可以像这样打印它的字段:

printf("Magic Number:\t%u\nBlock Size:\t%u\n etc", 
SuperBlock_t_Instance.magic_number, 
SuperBlock_t_Instance.block_size);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-02-13
    • 1970-01-01
    • 2010-09-25
    • 2011-10-18
    • 2018-10-10
    • 1970-01-01
    • 1970-01-01
    • 2023-02-21
    相关资源
    最近更新 更多