Why does fread mess with my byte order?

后端 未结 3 1451
无人共我
无人共我 2020-12-25 08:25

Im trying to parse a bmp file with fread() and when I begin to parse, it reverses the order of my bytes.

typedef struct{
    short magic_number;         


        
3条回答
  •  醉梦人生
    2020-12-25 09:10

    I assume this is an endian issue. i.e. You are putting the bytes 42 and 4D into your short value. But your system is little endian (I could have the wrong name), which actually reads the bytes (within a multi-byte integer type) left to right instead of right to left.

    Demonstrated in this code:

    #include 
    
    int main()
    {
        union {
            short sval;
            unsigned char bval[2];
        } udata;
        udata.sval = 1;
        printf( "DEC[%5hu]  HEX[%04hx]  BYTES[%02hhx][%02hhx]\n"
              , udata.sval, udata.sval, udata.bval[0], udata.bval[1] );
        udata.sval = 0x424d;
        printf( "DEC[%5hu]  HEX[%04hx]  BYTES[%02hhx][%02hhx]\n"
              , udata.sval, udata.sval, udata.bval[0], udata.bval[1] );
        udata.sval = 0x4d42;
        printf( "DEC[%5hu]  HEX[%04hx]  BYTES[%02hhx][%02hhx]\n"
              , udata.sval, udata.sval, udata.bval[0], udata.bval[1] );
        return 0;
    }
    

    Gives the following output

    DEC[    1]  HEX[0001]  BYTES[01][00]
    DEC[16973]  HEX[424d]  BYTES[4d][42]
    DEC[19778]  HEX[4d42]  BYTES[42][4d]
    

    So if you want to be portable you will need to detect the endian-ness of your system and then do a byte shuffle if required. There will be plenty of examples round the internet of swapping the bytes around.

    Subsequent question:

    I ask only because my file size is 3 instead of 196662

    This is due to memory alignment issues. 196662 is the bytes 36 00 03 00 and 3 is the bytes 03 00 00 00. Most systems need types like int etc to not be split over multiple memory words. So intuitively you think your struct is laid out im memory like:

                              Offset
    short magic_number;       00 - 01
    int file_size;            02 - 05
    short reserved_bytes[2];  06 - 09
    int data_offset;          0A - 0D
    

    BUT on a 32 bit system that means files_size has 2 bytes in the same word as magic_number and two bytes in the next word. Most compilers will not stand for this, so the way the structure is laid out in memory is actually like:

    short magic_number;       00 - 01
    <>        02 - 03
    int file_size;            04 - 07
    short reserved_bytes[2];  08 - 0B
    int data_offset;          0C - 0F
    

    So when you read your byte stream in the 36 00 is going into your padding area which leaves your file_size as getting the 03 00 00 00. Now if you used fwrite to create this data it should have been OK as the padding bytes would have been written out. But if your input is always going to be in the format you have specified it is not appropriate to read the whole struct as one with fread. Instead you will need to read each of the elements individually.

提交回复
热议问题