Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does packing a structure affect sub-structures?

We recently found some code submitted to our codebase, along the following lines:

#pragma pack(push,1)
struct xyzzy {
    BITMAPINFOHEADER header;
    char plugh;
    long twisty;
} myVar;

My question is: does the packing apply only to the immediate structure or might it affect the packing of the BITMAPINFOHEADER as well. I can't see the latter case being very useful since it would make the structure different to what you would get from the Windows API calls, for example. Case in point, let's assume the structure is:

typedef struct {
    char aChar;
    DWORD biSize;
} BITMAPINFOHEADER;

That structure would be vastly different with a packing of one rather than the default eight for Windows (32-bit anyway, may be sixteen for 64-bit).

Is the BITMAPINFOHEADER "protected" from the packing by virtue of the fact it's almost certainly be declared earlier? If it was declared as part of the outer declaration, would it be subject to the packing then?

like image 205
paxdiablo Avatar asked Mar 06 '18 07:03

paxdiablo


People also ask

How can structure padding be reduced?

In Structure, sometimes the size of the structure is more than the size of all structures members because of structure padding. Note: But what actual size of all structure member is 13 Bytes. So here total 3 bytes are wasted. So, to avoid structure padding we can use pragma pack as well as an attribute.

What is padding and packing in memory?

Structure packing is only done when you tell your compiler explicitly to pack the structure. Padding is what you're seeing. Your 32-bit system is padding each field to word alignment. If you had told your compiler to pack the structures, they'd be 6 and 5 bytes, respectively.

Why does structure padding happen?

The structure padding is automatically done by the compiler to make sure all its members are byte aligned. Here 'char' is only 1 byte but after 3 byte padding, the number starts at 4 byte boundary. For 'int' and 'double', it takes up 4 and 8 bytes respectively.


1 Answers

From the relevant documentation:

pack takes effect at the first struct, union, or class declaration after the pragma is seen. pack has no effect on definitions.

header is a member definition, so it isn't affected.

it was declared as part of the outer declaration, would it be subject to the packing then?

Yes, as it would be a struct declaration.

Also, as Lightness Races in Orbit remarks in a comment, a more convincing wording can be found immediately before:

To pack a class is to place its members directly after each other in memory.

i.e. it says nothing about what those members themselves contain, which may be data and/or padding. The fact that (as explored above) packedness is attached to a type would seem to reinforce that


Still, the documentation is vague enough, so it's best to test that this interpretation is correct; both gcc and VC++ behave as expected. Not that I'm particularly surprised - anything different would break havoc in the type system (taking a pointer to a member of a packed structure would actually provide a pointer to something different than its type says1).

The general idea is: once you finish defining a struct, its binary layout is fixed, and any of its instantiations will conform to it, including subobjects of packed structures. The current #pragma pack value is considered only when defining new structures, and when doing so the binary layout of the members is a fixed black box.


Notes

  1. To be honest, this is a bit of an x86-centric view; machines with stronger alignment requirements would object that even pointers to layout-correct but misaligned structures aren't kosher: although the offsets of fields relative to the given pointer are correct, they aren't really pointers that can be used as they are.

    OTOH, given a pointer to an unaligned object you can always detect that it's unaligned and memcpy it to a correctly-aligned location, so it's not as bad as a hypothetical pointer to a packed object, whose layout is effectively unknown unless you happen to know the packing of its parent.

like image 96
Matteo Italia Avatar answered Oct 18 '22 16:10

Matteo Italia