fread into struct reads data incorrectly

随声附和 提交于 2020-01-06 15:52:50

问题


I am trying to read a bitmap (.bmp) image header into a struct in c.

typedef unsigned short WORD;
typedef unsigned long DWORD;

typedef struct _BITMAPFILEHEADER {
    WORD Type;
    DWORD Size;
    WORD Reserved1;
    WORD Reserved2;
    DWORD OffBits;
} BITMAPFILEHEADER;

My code to read the bitmap file

FILE *fp;
BITMAPFILEHEADER header;

fp = fopen(file,"rb");
if (fp == NULL) {
    printf("cannot open file!\n");
    return 1;
}

fread(&header, sizeof(BITMAPFILEHEADER), 1, fp);

printf("Type: %02x\n", header.Type);
printf("Size: %04x\n", header.Size);
printf("Reserved: %02x\n", header.Reserved1);
printf("Reserved: %02x\n", header.Reserved2);
printf("Offset: %04x\n", header.OffBits);

What everything should equal:
Type: 0x424d
Size: 0x00060436
Reserved1: 0x00
Reserved2: 0x00
Offset: 0x00000436

What is actually happning (printf output):
Type: 0x424d
Size: 0x0006
Reserved: 0x002
Reserved: 0x436
Offset: 0x280000

(my os is 32-bit ubuntu if that helps)


回答1:


When reading this kind of files I think a good approach is to first read them as a stream of bytes (unsigned char) and then, if and when needed, to interpret part of the file contents according to the proper data types.

In your case, for instance, I would define the BITMAPFILEHEADER struct like this:

typedef struct _BITMAPFILEHEADER {
    unsigned char   Type[ 2 ];
    unsigned int    Size;          // Size of the BMP file in bytes 
    unsigned char   Reserved1[ 2 ];
    unsigned char   Reserved2[ 2 ];
    unsigned int    OffBits;       // Starting address of the pixel array 
} BITMAPFILEHEADER;

Then I would read the header contents as a block of 14 bytes and, at last, I would go on to fill the BITMAPFILEHEADER struct properly.

Below you can find a simple program that reads the header of a BMP file and prints it onto the screen.

int main
    (
    )
    {
    // Defines a few variables
    FILE*           fp   =  0;
    unsigned char   h[ 14 ];

    // Opens the BMP file
    fp   =   fopen( "img.bmp", "rb" );

    if ( fp == NULL )
        {
        printf( "Cannot open file\n" );
        return -1;
        }

    // Reads the BMP header (14 bytes)
    fread( h, 14, 1, fp );

    // Prints the header contents
    printf( "Type:     %02x%02x\n", h[ 0 ], h[ 1 ] );
    printf( "Size:     %02x%02x%02x%02x\n", h[ 2 ], h[ 3 ], h[ 4 ], h[ 5 ] );
    printf( "Reserved: %02x%02x\n", h[ 6 ], h[ 7 ] );
    printf( "Reserved: %02x%02x\n", h[ 8 ], h[ 9 ] );
    printf( "Offset:   %02x%02x%02x%02x\n", h[ 10 ], h[ 11 ], h[ 12 ], h[ 13 ] );

    return 0;
    }

NOTE 1 - Padding: From the BMP file format specification, we know that the header is 14-byte long while a printf( "%d", sizeof(BITMAPFILEHEADER) ) will show a different (greater!) number due to padding (see comments to your question).

NOTE 2 - Endiannes: When writing 2 or 4 bytes into a short or long respectively, you have to take into account endiannes. This means that you have to know how values are written into the file (as for the Bitmap header, they are represented using little endian notation) and how they are treated by your machine (probably in little endian notation).



来源:https://stackoverflow.com/questions/37779302/fread-into-struct-reads-data-incorrectly

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!