【问题标题】:Reading hexdump, fread读取 hexdump,fread
【发布时间】:2021-09-14 00:37:14
【问题描述】:

我有一个包含以下十六进制值的二进制文件。

用正确的代码读取这个二进制文件应该显示如下:

第一个图像中绿色突出显示的区域代表父亲、房间、吸引力、蛋糕的字段,分别输出值为 1,1,0,1。

我必须弄清楚我在下面编写的代码中使用什么数据类型为结构变量打印出 1,1,0,1。

我猜到 1101 来自十六进制“d”。但是,我不确定它是如何在 4 个不同的字段中打印出来的。

我知道我的问题与结构填充或位字段有关。但是,我仍然不确定我的代码和 fread 应该如何修改。

如果您能帮我解决这个问题或提供示例或相关阅读材料,我们将不胜感激。

#define MAX_HAT 9
#include<stdio.h>
#include<stdlib.h>

//struct variables
struct test
{
    short int land;
    float experience;
    char boys;
    short int angle;
    double industry;
    int thread;
    long int shoe;
    float kitty;
    unsigned char price;
    
    //not sure whether this is done correctly
    unsigned int father: 1;
    unsigned int room: 1;
    unsigned int attraction: 1;
    unsigned int cake: 1;
    
    int foot;
    char hat[MAX_HAT];
    char nest;
    float bean;
};

int main(int argc, char **argv)
{
    struct test t1;
    
    FILE *fp;

        //Input Checking Error
        if (argc < 2) {
                fprintf(stderr, "Usage: %s input_file\n", argv[0]);
                exit(1);
        }
    
        //binary file to open for reading
        fp = fopen(argv[1], "rb");
    
        //File Checking Error
        if (fp == NULL){
                fprintf(stderr, "Cannot open the file %s\n", argv[1]);
                exit(1);
        }

    //Print out struct fields
    printf("land, experience, boys, angle, industry, thread, shoe, kitty, price, father, room, attraction, cake, foot, hat, nest, bean \n");

    //Allocate the values into the struct
    while(fread(&t1.land, sizeof(t1.land), 1, fp) == 1)
    {
        fread(&t1.experience, sizeof(t1.experience), 1, fp);
        fread(&t1.boys, sizeof(t1.boys), 1, fp);
        fread(&t1.angle, sizeof(t1.angle), 1, fp);
        fread(&t1.industry, sizeof(t1.industry), 1, fp);
        fread(&t1.thread, sizeof(t1.thread), 1, fp);
        fread(&t1.shoe, sizeof(t1.shoe), 1, fp);
        fread(&t1.kitty, sizeof(t1.kitty), 1, fp);
        fread(&t1.price, sizeof(t1.price), 1, fp);
        fread(&t1.father, sizeof(t1.father), 1, fp);
        fread(&t1.room, sizeof(t1.room), 1, fp);
        fread(&t1.attraction, sizeof(t1.attraction), 1, fp);
        fread(&t1.cake, sizeof(t1.cake), 1, fp);
        fread(&t1.foot, sizeof(t1.foot), 1, fp);
        fread(&t1.hat, sizeof(t1.hat), 1, fp);
        fread(&t1.nest, sizeof(t1.nest), 1, fp);
        fread(&t1.bean, sizeof(t1.bean), 1, fp); 
                
    //Print out the outputs
    printf("%d, %f, %i, %i, %f, %d, %ld, %f, %u, %, %, %, %, %x, %s, %c, %f\n", t1.land, t1.experience, t1.boys, t1.angle, t1.industry, t1.thread, t1.shoe, t1.kitty, t1.price, t1.father, t1.room, t1.attraction, t1.cake,t1.foot, t1.hat, t1.nest, t1.bean);
        
    }

    //close the file
    fclose(fp);

    return 0;
}

【问题讨论】:

  • 可能是位域?
  • @kaylum 我需要对我的代码进行更改吗?
  • fread (&amp;t1, sizeof t1, 1, fp) 不起作用吗?现在数据应该被序列化,bur 对于许多学习读/写结构数据的人来说,一次读取一个结构(只要它是由相同架构上的相同编译器编写的)通常是预期的。您可以使用多个 fread() 调用,但如果存在填充,您将不会阅读您认为正在阅读的内容。

标签: c fread bit-fields


【解决方案1】:

线条

fread(&t1.father, sizeof(t1.father), 1, fp);
fread(&t1.room, sizeof(t1.room), 1, fp);
fread(&t1.attraction, sizeof(t1.attraction), 1, fp);
fread(&t1.cake, sizeof(t1.cake), 1, fp);

错了。您不能在bit-field 的成员上使用sizeof。这样做没有意义,因为位域成员可以小于一个字节,但sizeof 可以返回的最小大小是一个字节。还有fread能读取的最小单位是一个字节,而不是一个位。

在您的问题中,您声明“突出显示区域”(2 个字节)代表fatherroomattractioncake。但是,ISO C 只要求编译器支持int 大小的位域,在大多数平台上为 4 字节。您可能想尝试使用uint16_t(需要#include &lt;stdint.h&gt;)而不是unsigned int 作为位字段的基础数据类型,并希望您的编译器支持它。否则,输入数据的大小和位域的大小将不匹配,这会使事情变得更加复杂。

另外,另一个问题是 ISO C 没有指定位存储在位域中的顺序,即位是从右到左还是从左到右打包。因此,如果您的输入将来自另一端的位打包为您的编译器,那么您将不得不对此进行补偿。

使用按位与运算符&amp; 屏蔽单个位并使用&gt;&gt; 运算符移位它们可能更容易,而不是使用位域。结合使用这两个运算符可以提取单个位。

假设您有一个 a 类型为 uint16_t 的变量,您可以使用以下代码将输入文件中的两个字节读入该变量:

if ( fread( &a, sizeof a, 1, fp) != 1 )
    /*handle error*/;

之后,如果您假设 fatherleast-significant bit 中表示,那么您可以使用以下代码提取这些位并将它们分配给适当的变量:

bool father     = ( a & (0x01<<0) ) >> 0;
bool room       = ( a & (0x01<<1) ) >> 1;
bool attraction = ( a & (0x01<<2) ) >> 2;
bool cake       = ( a & (0x01<<3) ) >> 3;

请注意,要能够使用数据类型bool,您必须#include &lt;stdbool.h&gt;

更多信息请参见bitwise operations in C

如果您想用位域解决问题,那么我建议您更改行

unsigned int father: 1;
unsigned int room: 1;
unsigned int attraction: 1;
unsigned int cake: 1;

到下面

uint16_t father: 1;
uint16_t room: 1;
uint16_t attraction: 1;
uint16_t cake: 1;

并希望您的编译器支持它(gcc 支持)并希望编译器将这些位与您的输入从同一侧打包。

但是,另外一个问题是不能取位域的地址,因为它不一定从特定地址开始。因此,您无法将位域的地址传递给fread

因此,您必须将位域包装到它们自己的子结构中,如下所示:

struct test
{
    [...]

    struct
    {
        uint16_t father: 1;
        uint16_t room: 1;
        uint16_t attraction: 1;
        uint16_t cake: 1;
    } bitfield;

    [...]
};

现在,您仍然无法获取任何位域成员的地址。但是,您可以获取包含它们的struct 的地址,并将其传递给fread

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-10-25
    • 2013-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-27
    相关资源
    最近更新 更多