Monday, July 4, 2011

structure padding in C++

The size of a class can be changed simply by altering the order of its member declarations. Most processors require specific memory alignment on variables of certain types

Alignment rules

  1. bool variables can be byte aligned and appear at any byte boundary.
  2. short (2 byte) variables must be 2 byte aligned, they can appear at any even byte boundary. This means that 0x1005 is not a valid location for a short variable, but 0x1006 is.
  3. int (4 byte) variables must be 4 byte aligned, they can only appear at byte boundaries that are a multiple of 4 bytes. This means that 0x1006 is not a valid location for a long variable, but 0x1008 is.
So, structure padding occurs because the members of a structure must appear at the correct byte boundary. To achieve this, the compiler puts in padding so that the structure members appear in the correct location. And the size of the structure should be aligned to the memory so that the padding will occur at the end of the structure too.

struct INF
{
  bool        binfFlag1;
  unsigned short  usNumber;
  bool        binfFlag2;
  int         nNumber;
  bool        binfFlag3;
};


In this example, the alignment is as follows:
  • binfFlag1 (bool) can appear at any byte boundary (as per rule 1). So, imagine that the memory allocation for the structure INF starts at location 0x1004 and the first member binfFlag1 takes up that location for its 1 byte size storage.
  • usNumber (short) should have its first byte appearing at an even location. So it can not take up the location 0x1005. It will take the locations 0x1006 and 0x1007. The location 0x1005 is padded (as per rule 2).
  • binfFlag2 (bool) can then appear in the next available memory location. So it occupies 0x1008 (as per rule 1).
  • nNumber (int) must start at a location which is the multiple of 4. The next possible location for nNumber is 0x100C. So, there are 3 padding bytes between bool and int (as per rule 3).
  • bStatus (bool) then appears in the available memory location; however, because the structure contains an int member, the structure must be 4 byte aligned and must be a multiple of 4 bytes in size. Therefore, there are 3 padding bytes at the end of the structure.
The structure would be 16 bytes long.

For optimization, the structure can be re-written like this:

struct INF
{
 int              nNumber;
 unsigned short   usNumber;
 bool             binfFlag1;
 bool             binfFlag2;
 bool             binfFlag3;
};
 
The int appears at the correct byte alignment. The short will be correctly aligned, so no need for padding between the int and short. The three bools can appear at any location. The structure must be a multiple of 4 bytes in size since it contains an int, so 3 padding bytes appear after the last bool. Now, it is only 12 bytes long. So we saved 4 bytes by proper alignment of variables.

How to avoid structure padding using pragma?

The default compiler alignment is of 4 bytes. We need to change it to 1 byte.
For that, do the following steps:
  1. Push the current compiler alignment into the stack.
  2. Set the alignment into 1 byte.
  3. Declare the structure.
  4. Restore the default compiler alignment from the stack.
Example:

#pragma pack(push)  /* push current alignment to stack */
#pragma pack(1)     /* set alignment to 1 byte boundary */

struct MyPackedData
{
    char Data1;
    long Data2;
    char Data3;
};
#pragma pack(pop)   /* restore original alignment from stack */

Thus the structure size is 6 bytes.
 


See Also
C++ topics

No comments:

Post a Comment