【问题标题】:Read file into struct将文件读入结构
【发布时间】:2014-08-11 14:54:40
【问题描述】:

我正在尝试将文件的内容读入结构。 结构如下所示:

    typedef struct{
            unsigned char e_ident[EI_NIDENT] ;
            Elf32_Half e_type;
            Elf32_Half e_machine;
            Elf32_Word e_version;
            Elf32_Addr e_entry;
            Elf32_Off e_phoff;
            Elf32_Off e_shoff;
            Elf32_Word e_flags;
            Elf32_Half e_ehsize;
            Elf32_Half e_phentsize;
            Elf32_Half e_phnum;
            Elf32_Half e_shentsize;
            Elf32_Half e_shnum;
            Elf32_Half e_shstrndx;
    } Elf32_Ehdr;
extern Elf32_Ehdr elfH;

它基本上是一个 ELF 头文件。所以,无论如何我想将文件的内容加载到这个结构中。

函数如下所示。

Elf32_Ehdr elfH;
int load(char* fname){
        FILE* file = fopen(fname,"r");

        if(NULL == file) return 0;

        fread(&elfH, 1, 52, file);

        fclose(file);
        return 1;
}

它似乎无法正常工作。 elfH 的内容并不如预期。 可能是什么问题? 我应该

【问题讨论】:

  • 为什么不用sizeof elfH 而不是62
  • 您能否提供更多关于不符合预期的信息?当你将结构体的内存位置与文件中的数据进行比较时会发生什么?
  • 可能是字节序? (不确定 ELF 标头字段是小端还是大端。)
  • Elf32_Ehdr elfH; -->> fread(&elf, 1, 62, file); 名称不匹配。此外,声明与extern Elf32_Ehdr elfH; 冲突
  • 你在什么平台上?

标签: c struct fread


【解决方案1】:

这是我用来从 ELF 可执行文件中读取标头的代码。

FILE* fp = fopen(fname, "rb");
if(fp == NULL)
{
    printf("failed to load\n");
    exit(1);
}

Elf32_Ehdr hdr;
if (1 != fread(&hdr, sizeof(hdr), 1, fp))
{
    printf("failed to read elf header\n");
    exit(1);
}
// If program doesn't exit, header was read and can be worked with down here.

【讨论】:

    【解决方案2】:

    您必须在 fopen 的文件访问模式字符串 ("rb") 中添加 "b" 才能读取二进制数据。您的硬编码 elf 标头大小也可能不是一个好主意,因为您的 elf 标头结构的大小可能不完全是 62。sizeof(Elf32_Ehdr) 可能是一种更好的方法...

    【讨论】:

      【解决方案3】:

      也许你的问题是文件中的数据没有像你的程序期望的那样写在同一个endianness中。

      您可以通过比较十六进制的预期值和实际值来验证是否是这种情况。
      例如。如果您期望 0x12345678 但实际上得到 0x78563412 这绝对是字节顺序问题。

      有关解决方案,请参阅this 问题的答案。

      【讨论】:

        【解决方案4】:

        C 对structs 的内容如何在内存中打包和对齐做出了相当有限的保证。 Elf32_Ehdr 结构的元素是否实际上是连续的,这可能取决于编译器和平台。由于它们的大小都不同,我对此表示怀疑(如果您打印出 sizeof(Elf32_Ehdr) 并将其与标题的实际磁盘大小进行比较,您可能会看到差异)。

        如果您知道您正在阅读的标头长度为 52 个字节(如您的代码所示),那么您需要 fread 那么多,然后执行类似(大纲)的操作

        #define HDR_SIZE 52
        typedef unsigned char byte;
        Elf32_Ehdr hdr;
        
        byte buf[HDR_SIZE];
        
        fread(buf, HDR_SIZE, 1, fp);
        
        hdr.e_version = *(Elf32_Word*)&buf[1];
        ...
        

        (我猜Elf32_Half 是半字节,所以e_version 在缓冲区的字节 1 和 2(0 偏移)中)。

        我还没有测试过,但我希望你能明白。

        那么有字节性问题要你操心……

        【讨论】:

          【解决方案5】:

          正如dragosht 指出的那样,如果您在某种Windows 机器上,您可能需要打开二进制文件。

          您也有可能遇到对齐问题。 出于性能原因,结构可以自动插入额外的字段以帮助保持正确的地址对齐。

          如果您正在读取以二进制模式从相同结构写入的文件,我不希望看到这个问题。

          【讨论】:

          • 总的想法是我自己创建标题(我会在我的程序中填充结构,然后将其写入文件)......然后,在我的其他点程序我会读它,所以形式应该是一样的。我可以用 .txt 文件对此进行测试吗?例如,我有一个包含 52 个字符的单词的文件(每个字符是一个字节,所以大小应该是 52 个字节)。我的结构的内容应该是什么?主要问题是,我可以用保存为 .bin 的文本文件来测试吗?
          • 没有。以 .bin 扩展名保存的文本文件仍然是文本文件。你在哪个平台上运行?
          • 我在 Visual Studio 2010、Windows 7 上运行它。
          • 肯定是一个问题。读取时必须打开文件“rb”,写入时必须打开文件。
          • 我建议编写一个与您的应用程序分开的测试程序,该程序定义一个测试结构,填充它,将其写入二进制文件。然后它创建另一个结构并从二进制文件中读取它。然后在这两个结构上使用 memcmp 来查看它们是否相同。这将为您提供一个测试的地方,以使技术正确。当您需要刷新技术时,您将能够再次参考它。
          【解决方案6】:

          您的代码具有向后的 fread,这使得 if 语句不正确。如果项目被读取,fread 返回数字。如果您向后提供大小参数,那么它将返回读取的字节数。因此,解决方案是以相反的顺序将两个大小参数提供给 fread。

          int main(int argc, char ** argv)
          {
              printf("Reading %s\n", argv[1]);
              FILE* fp = fopen(argv[1], "rb");
              if(fp == NULL)
              {
                      printf("file not opened\n");
                      exit(-1);
              }
          
              Elf32_Ehdr * header = malloc(sizeof(Elf32_Ehdr));
              int value = fread(header, sizeof(Elf32_Ehdr), 1, fp);
              //int value = fread(header, 1, sizeof(Elf32_Ehdr), fp); // incorrect order
              printf("Read %d items\n", value);
              if (value != 1)
              {
                      printf("failed to read elf header\n");
                      exit(-1);
              }
              printf("Majick %c%c%c%c",header->e_ident[0],header->e_ident[1], header->e_ident[2], header->e_ident[3]);
              fclose(fp);
          }
          

          【讨论】:

            猜你喜欢
            • 2021-02-13
            • 2016-10-24
            • 1970-01-01
            • 1970-01-01
            • 2016-06-11
            • 2012-12-26
            • 1970-01-01
            相关资源
            最近更新 更多