What is a "packed" structure in C?
When structures are defined, the compiler is allowed to add paddings (spaces without actual data) so that members fall in address boundaries that are easier to access for the CPU.
For example, on a 32-bit CPU, 32-bit members should start at addresses that are multiple of 4 bytes in order to be efficiently accessed (read and written). The following structure definition adds a 16-bit padding between both members, so that the second member falls in a proper address boundary:
struct S {
int16_t member1;
int32_t member2;
};
The structure in memory of the above structure in a 32-bit architecture is (~ = padding):
+---------+---------+
| m1 |~~~~| m2 |
+---------+---------+
When a structure is packed, these paddings are not inserted. The compiler has to generate more code (which runs slower) to extract the non-aligned data members, and also to write to them.
The same structure, when packed, will appear in memory as something like:
+---------+---------+
| m1 | m2 |~~~~
+---------+---------+
It instructs the compiler to not add any padding between members of the struct
.
See, for example, this page.
Let me explain the concept of padding in structures and then packed structures by taking an example.
And then let us see why packing is required.
Padding:
struct eg_struct
{
unsigned char abc;
unsigned int xyz;
}
When the structure is declared as above on a 16 bit architecture, the variable abc
would be assigned some address. The next address is not assigned to variable xyz
, instead one extra byte is added, and then the next address would be assigned to the variable xyz
.
In the end, the structure looks something like below:
struct eg_struct
{
unsigned char abc;
unsigned char paddedbytes[1];
unsigned int xyz;
}
Padding makes addresses of member variables easily accessible to the microcontroller. The disadvantage is extra unnecessary bytes that come into the picture.
Packing:
If same structure is declared using the attribute “packed
”, the extra byte will not be added after the variable abc
.
Let me give one example where packing is needed:
Consider a microcontroller interfaced with an EEPROM where some structure is being stored.
Imagine a function writing to the EEPROM would look as below:
Write_EEPROM(EEPROM address, Ram address, Byte count);
Now if packing is not done, the extra padded bytes would occupy space in the EEPROM, which is of no use.