将二进制文件读入结构以及字节顺序问题

Read binary file into struct and also problems with endianness

我想将二进制文件 image.dd 读入 struct teststruct *test;。基本上有两个问题:


1.由于小/大端顺序错误。

printf("%02x", test->magic); 只是给我 534b554c 而不是 4c55b453 (也许这与下一部分的“主要问题”有关)。它只是“一个值”。例如,printf("%c", test->magic); 给出 L 而不是 LUKS


2。 test->version.

无输出

uint16_t version; in struct teststruct 没有输出。这意味着,我调用 printf("%x ", test->version); 但没有结果。


这是 exampleh.h 其中包含 struct:

#ifndef _EXAMPLEH_H
#define _EXAMPLEH_H

#define MAGIC_L     6

struct teststruct {
    char                magic [MAGIC_L];
    uint16_t            version;
};

#endif

这是 main 代码:

using namespace std;

#include <stdint.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include "exampleh.h"

struct teststruct *test;

int main() {
    FILE *fp = fopen("C:\image.dd", "rb");     // open file in binary mode

    if (fp == NULL) {
        fprintf(stderr, "Can't read file");
        return 0;
    }
    fread(&test,sizeof(test),1,fp);
    //printf("%x ", test->magic);   //this works, but in the wrong order because of little/big endian
    printf("%x ", test->version);   //no output at all

    fclose(fp);

    return 0;
}

这里是 image.dd 的前 114 个字节:

4C 55 4B 53 BA BE 00 01 61 65 73 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 78 74 73 2D 70 6C 61 69 
6E 36 34 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 73 68 61 32 35 36 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 40

struct teststruct *test; 指向 NULL,因为它是在全局命名空间中定义的。你没有为这个指针分配内存,所以test->version是UB。

fread(&test,sizeof(test),1,fp);也是错误的,这将读取一个指针,而不是结构的内容。

一个简单的解决方法是将 test 更改为 struct teststruct 而不是指向它的指针。

using namespace std;

#include <stdint.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include "exampleh.h"

struct teststruct test; //not a pointer anymore

int main() {
    FILE *fp = fopen("C:\image.dd", "rb");     // open file in binary mode

    if (fp == NULL) {
        fprintf(stderr, "Can't read file");
        return 0;
    }
    fread(&test,sizeof(test),1,fp);
    //printf("%x ", test.magic);   //this works, but in the wrong order because of little/big endian
    printf("%x ", test.version);   //no output at all

    fclose(fp);

    return 0;
}
  • 您必须分配结构并将数据读入结构,而不是直接读入指针。如果您打算只读取一个结构,则不需要为该结构声明指针。
  • printf("%x ", test->magic); 调用 未定义的行为 因为指针(从数组自动转换)被传递到需要 unsigned int 的地方。

在这种情况下,观察到的行为是因为:

首先,fread(&test,sizeof(test),1,fp);从文件中读取前几个字节作为指针值。

然后,printf("%02x", test->magic); 打印文件中的第一个 4 字节整数,因为 test->magic 是(转换为)指向位于结构顶部的数组的指针,以及该数组与结构本身的地址相同,因此打印从文件读取的地址。更幸运的是,从哪里读取 4 字节整数和地址(指针)作为函数参数是相同的。

最后,您没有从 printf("%x ", test->version); 获得任何输出,因为不幸的是,从文件中读取的地址位于不可读的区域并且尝试读取该区域导致了分段错误。

固定码:

using namespace std;

#include <stdint.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include "exampleh.h"

struct teststruct test; // allocate structure directly instead of pointer

int main() {
    FILE *fp = fopen("C:\image.dd", "rb");     // open file in binary mode

    if (fp == NULL) {
        fprintf(stderr, "Can't read file");
        return 0;
    }
    fread(&test,sizeof(test),1,fp); // now structure is read instead of pointer
    for (int i = 0; i < 6; i++) {
        printf("%02x", (unsigned char)test.magic[i]); // print using proper combination of format and data
    }
    printf(" ");
    printf("%x ", test.version); // also use . instead of ->

    fclose(fp);

    return 0;
}