cbinaryfilesbmp

Writting to binary file a struct adds 0s


I want to create a simple BMP and save it. Because I don't want to complicate things I decided to follow the example from Example 1 and just change the required things, like width and stuffs like that.

I save the BMP_header in the following struct:

typedef struct{

    unsigned short file_type; // hex for "BM"
    unsigned int file_size;
    unsigned int empty_space; // empty space always 0x0
    unsigned int offset; // always 0x36000000

}BMP_header;

Also I have created a function that initialise one struct:

BMP_header* BMP_header_init(unsigned int bmp_data){

    BMP_header* coppy = (BMP_header*)malloc(sizeof(BMP_header));

    coppy->file_type = 0x4d42;
    coppy->file_size = (54 + bmp_data) << 24;
    coppy->empty_space = 0;
    coppy->offset = 0x36000000;

    return coppy;

}

To write the header to a file, I have tried the traditional method

fwrite(header, sizeof(*header), 1, f);

header being the BMP_header_init result. The problem is that my expected output doesn't match what I would expected, simply adding 0s for no reason. I have tried to write every field of the field, thinking that the padding from the unsigned short field would be the cause.

The expected output should be, without the space:

42 4D 46 00 00 00 00 00 00 00 36 00 00 00

that matches the Example 1 from wikipedia, but for some reasons I get an extra 3 pair of 0s (I now they are in hex):

42 4D *00 00 00* 46 00 00 00 00 00 00 00 36 00 00 00

The only thing I do in main is to build a struct and then write it to the file:

FILE* f = fopen("img.bmp", "wb");

BMP_header* header = BMP_header_init(16); // to match the example

fwrite(header, sizeof(*header), 1, f);

Solution

  • With bmp_data equal to 16, your expression (54 + bmp_data) << 24 creates the value 70 << 24 = 1,174,405,120 = 4600000016. As seen from the fact that the short containing the value 4D4216 is written to the file with the 4216 byte first and then the 4D16 byte, your C implementation stores the least significant byte first. So 4600000016 produces bytes 0016, 0016, 0016, and 4616 in the file, in that order.

    There is no need for the << 24. Remove it. Also change coppy->offset = 0x36000000; to coppy->offset = 0x36;.

    Note that this code will not be portable, as other C implementations may store the bytes of objects in different orders.

    Additionally, I would have expected a typical C implementation to insert two bytes of padding after the unsigned short file_type and before the unsigned int file_size in the structure, to keep the unsigned int aligned to a multiple of four bytes. It is odd that does not appear between the two members in the file.