3

I am writing some code to read bitmap files.

Here is the struct I am using to read the bitmap header. See also:

https://msdn.microsoft.com/en-us/library/windows/desktop/dd183374(v=vs.85).aspx

struct BITMAPFILEHEADER
{
        WORD  bfType; // 2
        DWORD bfSize; // 6
        WORD  bfReserved1; // 8
        WORD  bfReserved2; // 10
        DWORD bfOffBits; // 14
}; // should add to 14 bytes

If I put the following code in my main function:

std::cout << "BITMAPFILEHEADER: " << sizeof(BITMAPFILEHEADER) << std::endl;

the program prints:

BITMAPFILEHEADER: 16

It appears to be re-aligning the data in the struct on 4-byte boundaries, presumably for efficiency. Of course this renders me unable to read a bitmap... Even though microsoft, and others, specifiy this is the way to do it...

How can I prevent the structure re-alignment?

FreelanceConsultant
  • 13,167
  • 27
  • 115
  • 225
  • Why exactly does this renders it unusable? You do realize you should deserialize data into your program? – Passer By Jun 19 '17 at 00:29
  • Because when I read sizeof(BITMAPFILEHEADER) 16 bytes are read not 14. – FreelanceConsultant Jun 19 '17 at 00:31
  • Are you creating this structure definition yourself? The `windows.h` header already includes this with the requisite set of `pragma`'s to make the size 14. – PaulMcKenzie Jun 19 '17 at 00:35
  • That is super annoying, but couldn't you just read 14 bytes? – Passer By Jun 19 '17 at 00:35
  • Unfortunately not as some of the bytes are miss aligned – FreelanceConsultant Jun 19 '17 at 00:36
  • I'm using Linux so no windows.h I'm afraid – FreelanceConsultant Jun 19 '17 at 00:36
  • @user3728501 -- Then the issue is not with that structure. The issue is not doing the research into how to pack the structure using whatever facilities the compiler you're using has to pack structs. – PaulMcKenzie Jun 19 '17 at 00:38
  • @PaulMcKenzie you can do that? Even if it means `bfSize` gets misaligned? – Passer By Jun 19 '17 at 00:38
  • @PasserBy [Live example using Visual C++](http://rextester.com/BVUB6390) – PaulMcKenzie Jun 19 '17 at 00:38
  • @PaulMcKenzie Are you going to post an answer since you seem to know what the solution is? Since I'm not on a windows platform I can't open windows.h and see what trickey is in there. – FreelanceConsultant Jun 19 '17 at 00:42
  • @user3728501 I actually meant for you to manually assign the fields from the 14 bytes – Passer By Jun 19 '17 at 00:42
  • @PasserBy As in by reading 2 bytes into a short, then 4 bytes into an int, etc until the contents is read? Yes I could do this, but it isn't very nice. Probably won't be very efficient when calling read() either, but I guess that isn't a big issue. – FreelanceConsultant Jun 19 '17 at 00:43
  • @user3728501 -- You need to research how your compiler packs structs and how to override the default packing. For Visual C++, it is done using `#pragma pack`. Having said that, whatever compiler you're using should already have a version of the windows.h header in some shape or form so that is usable right-out-the-box. Trying to recreate structs from Windows h on your own is going to be an issue for other such structs. – PaulMcKenzie Jun 19 '17 at 00:45
  • Your performance will **not** take a hit simply because you read some bytes of header slightly differently, unless all you do is read headers – Passer By Jun 19 '17 at 00:46
  • I have never seen a (pack) pragma that did not work, but I have seen different names for them in different compilers, so not so portable. There are several standard C++ coding alternatives (i.e. no pragma needed) Excuse me while I search my archives... – 2785528 Jun 19 '17 at 03:23
  • One choice for you to consider is to explicitly define the private data and provide suitable access. The small field count of 5 makes this practical, and easy to understand. See also https://stackoverflow.com/a/2554472/2785528. – 2785528 Sep 18 '17 at 18:22
  • @user3728501, take a look at [this](https://stackoverflow.com/a/12654801/8597205) answer for cross-platform aligning – A. Knorre Sep 22 '17 at 16:02

2 Answers2

5

The solution I found which works on gcc compilers, under linux:

struct BITMAPFILEHEADER
{
        WORD  bfType;
        DWORD bfSize;
        WORD  bfReserved1;
        WORD  bfReserved2;
        DWORD bfOffBits;
} __attribute__((packed));

There is probably a better, more cross compiler/platform way of doing things, but I don't know what it is.

FreelanceConsultant
  • 13,167
  • 27
  • 115
  • 225
  • *There is probably a better, more cross compiler/platform way of doing things* -- [pragmas used by gcc](https://gcc.gnu.org/onlinedocs/gcc-4.5.1/gcc/Structure_002dPacking-Pragmas.html) – PaulMcKenzie Jun 19 '17 at 01:00
1

To avoid this, you can obviously designate the compiling granularity. Just use this switch:

##pragma pack(1)

This tells the compiler to align to 1-byte boundaries (do nothing)

To resume normal padding (from before the previous #pragma pack):

#pragma pack(pop)
Mark
  • 18
  • 5