2

I'm currently trying to read a bitmap file header using the following code:

#include <fstream>
using namespace std;

struct BitMapFileHeader {
    uint16_t bfType;
    uint32_t bfSize;
    uint16_t bfReserved1;
    uint16_t bfReserved2;
    uint32_t bfOffBits;
} file_header;

int main() {
    ifstream fin;
    fin.open("input.bmp", ios::binary);

    fin.read(reinterpret_cast<char*>(&file_header), sizeof(file_header));

}

The first few bytes of my file are 42 4D 36 53 07 00 00 00. file_header.bfType shows the correct value of 19778contained in the 1st and 2nd bytes, however filder_header.bfSize shows 7, which is stored in the 5th byte and it seems to skip the 3rd and 4th bytes.

It appears that I have encountered an issue that was mentioned in the comment of the second answer of this question. Despite identifying the issue, I have no clue how to resolve it. Can someone point me in the right direction?

Edit: some do not recommend packing struct members due to performance issues with unaligned memory access. Apart from populating each struct member one by one, is there any way to avoid this performance penalty?

George Tian
  • 401
  • 7
  • 16
  • 1
    More than likely you need to change the packing of the struct to byte-aligned. That is done using a `#pragma`, a compiler extension or some compiler option, depending on the compiler. – PaulMcKenzie Nov 17 '20 at 09:08
  • You should mention what compiler you're using. – PaulMcKenzie Nov 17 '20 at 09:19
  • @PaulMcKenzie this is part of a question that will be submitted to an online judging system, and the compiler along with the C++ standard seems to change randomly, so I cannot give a definite answer. – George Tian Nov 17 '20 at 09:23
  • This is not a C++ standard issue -- it is solely a compiler issue. It is compiler-dependent on how to set the structure alignment. [See this](https://en.wikipedia.org/wiki/Data_structure_alignment). For g++, it is done using `__attribute__((packed))`, for Visual C++, it is `#pragma pack(1)`, etc. along with the `push` and `pop` set of `#pragma`s, etc. As to your edit, this has nothing to do with performance. You are trying to "overlay" the bitmap header onto a struct without any failures. – PaulMcKenzie Nov 17 '20 at 09:25
  • @PaulMcKenzie thank you. `#pragma pack(1)` worked, so I'd assume the compiler is Visual C++ – George Tian Nov 17 '20 at 09:31
  • I guess it probably is Visual C++. But you should use the push and pop pragmas also. If you set `#pragma pack(1)` with out push / pop, then all of your structs will be packed from where the `#pragma` was specified. To prevent this, you should use `push` and `pop` to make sure only the `BitmapFileHeader` is packed. – PaulMcKenzie Nov 17 '20 at 09:33

2 Answers2

1

Use __attribute__ ((packed)) after struct:

struct BitMapFileHeader {
    uint16_t bfType;
    uint32_t bfSize;
    uint16_t bfReserved1;
    uint16_t bfReserved2;
    uint32_t bfOffBits;
} __attribute__ ((packed)) file_header;

TCvD
  • 600
  • 2
  • 8
0

The issue is that the struct is not byte-packed, thus there is padding added between the members.

Since you are using Visual C++, use #pragma pack to byte-pack the struct, along with the push and pop set of #pragmas to limit the byte-packing to the struct you're interested in:

#pragma pack(push)
#pragma pack(1)

struct BitMapFileHeader {
    uint16_t bfType;
    uint32_t bfSize;
    uint16_t bfReserved1;
    uint16_t bfReserved2;
    uint32_t bfOffBits;
} file_header;

#pragma pack(pop)
PaulMcKenzie
  • 34,698
  • 4
  • 24
  • 45