0
0
Embedded Cprogramming~15 mins

Struct packing and alignment in Embedded C - Deep Dive

Choose your learning style9 modes available
Overview - Struct packing and alignment
What is it?
Struct packing and alignment in C control how data is arranged in memory inside a structure. Alignment means placing data at memory addresses that match the size of the data type for faster access. Packing removes extra spaces added for alignment, making the structure use less memory but possibly slower to access. These rules affect how your program reads and writes data efficiently on hardware.
Why it matters
Without proper alignment, processors may take longer to read data or even cause errors on some systems. Packing helps save memory, which is critical in embedded systems with limited space. If you ignore these concepts, your program might run slower, crash, or behave unpredictably, especially when communicating with hardware or other programs expecting specific data layouts.
Where it fits
Before learning struct packing and alignment, you should understand basic C data types and how memory works. After this, you can learn about memory-mapped hardware registers, optimization techniques, and cross-platform data communication where precise data layout is crucial.
Mental Model
Core Idea
Struct packing and alignment arrange data in memory to balance speed and space by adding or removing gaps between fields.
Think of it like...
Imagine packing a suitcase: alignment is like placing heavy items at the bottom for stability (correct position), while packing is squeezing everything tightly to fit more clothes but risking wrinkles or damage.
Structure Memory Layout:
┌───────────────┐
│ Field A (4B)  │
├───────────────┤
│ Padding (0-3B)│ <- Added for alignment
├───────────────┤
│ Field B (2B)  │
├───────────────┤
│ Padding (0-2B)│ <- Added for alignment
├───────────────┤
│ Field C (1B)  │
└───────────────┘

With packing:
┌───────────────┐
│ Field A (4B)  │
├───────────────┤
│ Field B (2B)  │
├───────────────┤
│ Field C (1B)  │
└───────────────┘
Build-Up - 7 Steps
1
FoundationUnderstanding basic struct layout
🤔
Concept: How C stores struct fields in memory sequentially with possible gaps.
In C, a struct groups variables together. Each field is stored in memory one after another. However, the compiler may add empty spaces called padding between fields to align data properly. For example, a 1-byte char followed by a 4-byte int may have 3 bytes of padding after the char to align the next field.
Result
Memory layout includes fields plus padding bytes, making struct size larger than sum of fields.
Knowing that structs include padding helps you understand why their size can be bigger than expected.
2
FoundationWhat is data alignment?
🤔
Concept: Data alignment means placing data at memory addresses divisible by their size for efficient access.
Processors read data faster when it is stored at addresses matching the data size. For example, a 4-byte int is best stored at an address divisible by 4. If not aligned, the processor may need extra steps to read or write the data, slowing down the program.
Result
Fields are placed at aligned addresses, sometimes requiring padding bytes before them.
Understanding alignment explains why padding exists and why it improves speed on many processors.
3
IntermediateHow padding affects struct size
🤔Before reading on: do you think padding always increases struct size or only sometimes? Commit to your answer.
Concept: Padding is added to align fields and the overall struct size to the largest field's alignment requirement.
Padding can appear between fields and at the end of the struct to ensure the whole struct size is a multiple of the largest alignment. For example, a struct with a 4-byte int and a 2-byte short may have 2 bytes padding at the end to align the struct size to 4 bytes.
Result
Struct size may be larger than sum of fields plus internal padding due to end padding.
Knowing about end padding helps avoid bugs when arrays of structs are used, ensuring each element starts aligned.
4
IntermediateUsing #pragma pack to control packing
🤔Before reading on: do you think packing removes all padding or only some? Commit to your answer.
Concept: The #pragma pack directive tells the compiler to reduce or remove padding between fields.
By using #pragma pack(1), you tell the compiler to pack fields with 1-byte alignment, removing padding. This saves memory but may cause slower access or hardware faults on some systems. Example: #pragma pack(1) struct S { char c; int i; }; #pragma pack() // reset packing
Result
Struct fields are tightly packed with no padding, reducing size but possibly hurting performance.
Understanding packing trade-offs helps you decide when saving memory is worth slower access or hardware risks.
5
IntermediateAlignment and packing on different architectures
🤔
Concept: Different processors have different alignment requirements and tolerances for unaligned access.
Some CPUs allow unaligned access but slower, others cause crashes. For example, ARM often requires strict alignment, while x86 is more forgiving. Packing structs on strict CPUs can cause faults if fields are not aligned properly.
Result
Code using packed structs must consider target CPU alignment rules to avoid crashes.
Knowing CPU alignment rules prevents subtle bugs and crashes in embedded systems.
6
AdvancedImpact of packing on performance and correctness
🤔Before reading on: do you think packed structs always improve performance by saving memory? Commit to your answer.
Concept: Packing reduces memory but can degrade performance and cause hardware faults due to unaligned access.
While packed structs save memory, accessing unaligned fields may require extra CPU cycles or cause exceptions. This is critical in embedded systems where timing and reliability matter. Developers must balance memory savings with safe and fast access.
Result
Packed structs may cause slower code or crashes if used without care.
Understanding this trade-off is key to writing reliable, efficient embedded code.
7
ExpertCompiler internals and ABI influence on layout
🤔Before reading on: do you think struct layout is fully controlled by the programmer or also by compiler and platform rules? Commit to your answer.
Concept: Struct layout is determined by compiler rules and the platform's Application Binary Interface (ABI), not just programmer directives.
Compilers follow ABI rules to ensure compatibility between compiled code and libraries. These rules define alignment, padding, and field order. Even with packing directives, compilers may enforce minimum alignment for correctness. Understanding ABI helps debug layout issues and write portable code.
Result
Struct layout can vary between compilers and platforms, affecting binary compatibility.
Knowing ABI influence prevents surprises when sharing data between modules or systems.
Under the Hood
At runtime, the CPU accesses memory in chunks matching its word size. The compiler arranges struct fields so each starts at an address divisible by its size, adding padding bytes if needed. This alignment allows the CPU to read or write data in one operation. Packing directives override default alignment, forcing the compiler to place fields back-to-back, which may cause the CPU to perform multiple operations or handle exceptions for unaligned access.
Why designed this way?
Alignment rules were created to match hardware capabilities and optimize speed. Early CPUs required strict alignment to avoid faults. Packing was introduced as a trade-off to save memory in constrained environments like embedded systems. The ABI standardizes these rules to ensure different code modules can work together safely and efficiently.
Memory Layout Flow:
┌───────────────┐
│ Field 1       │
├───────────────┤
│ Padding if    │
│ needed        │
├───────────────┤
│ Field 2       │
├───────────────┤
│ Padding if    │
│ needed        │
├───────────────┤
│ ...           │
├───────────────┤
│ End Padding   │
└───────────────┘

Packing Directive:
┌───────────────┐
│ Field 1       │
├───────────────┤
│ Field 2       │
├───────────────┤
│ ...           │
└───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does packing always improve program speed? Commit to yes or no.
Common Belief:Packing structs always makes programs faster because they use less memory.
Tap to reveal reality
Reality:Packing can slow down programs because unaligned data access is slower or causes faults on some CPUs.
Why it matters:Assuming packing improves speed can lead to slower or unstable embedded applications.
Quick: Is struct layout identical across all compilers and platforms? Commit to yes or no.
Common Belief:Struct layout is the same everywhere if the code is the same.
Tap to reveal reality
Reality:Struct layout depends on compiler and platform ABI rules, so it can differ, affecting binary compatibility.
Why it matters:Ignoring this can cause bugs when sharing data between different systems or libraries.
Quick: Does #pragma pack(1) guarantee no padding at all? Commit to yes or no.
Common Belief:#pragma pack(1) removes all padding bytes completely.
Tap to reveal reality
Reality:Some padding may still be added by the compiler to meet minimum alignment or ABI requirements.
Why it matters:Expecting zero padding can cause incorrect assumptions about struct size and layout.
Quick: Can unaligned access cause hardware faults on all CPUs? Commit to yes or no.
Common Belief:All CPUs handle unaligned access safely without issues.
Tap to reveal reality
Reality:Many embedded CPUs, like ARM Cortex-M, generate faults on unaligned access, requiring careful alignment.
Why it matters:Ignoring CPU behavior can cause crashes in embedded systems.
Expert Zone
1
Some compilers reorder struct fields internally for better packing unless explicitly prevented, affecting layout.
2
Alignment requirements can differ for pointers versus scalar types, influencing struct design.
3
Using packed structs with bit-fields can produce unexpected padding and alignment issues.
When NOT to use
Avoid packing when performance and stability are critical, especially on CPUs that fault on unaligned access. Instead, use natural alignment and optimize field order. For cross-platform data exchange, use serialization formats or explicit byte arrays.
Production Patterns
In embedded firmware, packed structs are used for hardware register maps and communication protocols where exact layout matters. Developers carefully balance packing with alignment to meet memory constraints without causing faults. ABI-aware tools verify struct layouts for compatibility.
Connections
Memory-mapped I/O
Builds-on
Understanding struct packing is essential to correctly map hardware registers to memory addresses without errors.
Data serialization
Builds-on
Knowing how data is aligned and packed helps design portable binary formats for network or file communication.
Warehouse storage optimization
Analogy-based cross-domain
Just like packing boxes efficiently in a warehouse saves space but may slow retrieval, struct packing balances memory use and access speed.
Common Pitfalls
#1Ignoring padding causes incorrect struct size assumptions.
Wrong approach:struct S { char c; int i; }; // Assume sizeof(S) == 5 bytes
Correct approach:struct S { char c; int i; }; // sizeof(S) is typically 8 bytes due to padding
Root cause:Misunderstanding that compiler adds padding to align fields.
#2Using packed structs without considering CPU alignment causes crashes.
Wrong approach:#pragma pack(1) struct S { char c; int i; }; // Accessing i may cause fault on ARM Cortex-M
Correct approach:Use natural alignment or access fields carefully with memcpy or aligned buffers.
Root cause:Not knowing CPU hardware restrictions on unaligned access.
#3Assuming #pragma pack(1) removes all padding always.
Wrong approach:#pragma pack(1) struct S { char c; int i; }; // Expect sizeof(S) == 5 bytes on all compilers
Correct approach:Check sizeof(S) on target compiler; some add minimal padding for ABI compliance.
Root cause:Believing packing directives override all compiler and ABI rules.
Key Takeaways
Struct packing and alignment control how data fields are arranged in memory to balance speed and memory use.
Alignment adds padding to place fields at addresses matching their size, improving CPU access speed.
Packing removes padding to save memory but can cause slower access or hardware faults on some CPUs.
Compiler and platform ABI rules influence struct layout beyond programmer directives.
Understanding these concepts is critical for writing efficient, reliable embedded C programs.