How to Use Offsetof() and Structure Padding to Save Memory in C

You save memory by using `offsetof()` to spot hidden padding in your structs, then reorder members from largest to smallest-like putting `long` or pointers before `char`-to cut waste. On ESP32 or Arduino Due, this shrinks a bloated 24-byte struct down to 16. Use `#pragma pack(1)` carefully to remove gaps entirely, but watch for crashes on ARM. Bitfields pack flags snugly into leftover space. There’s more to mastering tight data layouts where every byte counts.

We are supported by our audience. When you purchase through links on our site, we may earn an affiliate commission, at no extra cost for you. Learn moreLast update on 4th June 2026 / Images from Amazon Product Advertising API.

Notable Insights

  • Use `offsetof()` to measure memory offsets and identify padding between struct members.
  • Rearrange struct members from largest to smallest to minimize alignment-induced padding.
  • Avoid placing small types like char before larger types like long to prevent wasted bytes.
  • Apply `#pragma pack(1)` to eliminate padding, but beware of performance or alignment issues.
  • Utilize bitfields within unused padding space to store flags without increasing struct size.

Understand Structure Padding and Alignment

Memory quirks in C structs can sneak up on you like an unnoticed power draw in a battery-powered robot, but understanding padding and alignment keeps your microcontroller projects lean and efficient. When you declare a struct, the compiler adds padding to meet each member’s alignment requirement, ensuring data is accessed at memory addresses divisible by their size. For example, placing a char (1 byte) before a long (8 bytes) wastes 7 bytes of padding on a 64-bit system-your struct size jumps to 16 bytes instead of 9. The largest member dictates the structure’s alignment, so a double forces 8-byte alignment, affecting the whole struct’s size. Without proper alignment, devices like Arduinos on certain architectures suffer performance hits or even crashes. You’re not just storing data-you’re managing memory layout. Smart member ordering cuts padding, saves space, and boosts efficiency in resource-limited embedded systems.

Measure Padding With Offsetof()

You’ve seen how misaligned struct members can waste precious bytes with hidden padding, especially on microcontrollers where every kilobyte counts, and now it’s time to shine a light on exactly where that padding hides. Use the `offsetof()` macro from `` to probe your struct’s memory layout and expose both internal and trailing padding. The offset reveals how alignment rules bump each struct member down to satisfy data type requirements. For example, if `offsetof(struct foo, long_var)` returns 8 after a char, 7 bytes of padding were inserted. Compare adjacent offsets to catch internal padding, and use `sizeof()` minus the final member’s offset and size to measure trailing padding.

MemberOffsetPadding Before
char a00
int b43 (internal)
long c80
short d166 (internal)
Total struct size: 24, Trailing padding: 6 bytes

Rearrange Members by Size to Minimize Waste

Smart struct design isn’t just about what you include-it’s about the order you put things in, and how that choice directly impacts memory use on tight systems like Arduinos or ARM-based microcontrollers. You can drastically cut padding bytes by rearranging members by size. Place the largest member first-like a `long` or pointer-followed by smaller data types. This follows alignment rules, letting `int`, `short`, and `char` fill gaps left behind. For example, putting `char` before `int` and `long` adds 11 padding bytes, bloating your struct instance to 24 bytes. But reorder it with the 8-byte `long` first, then `int`, then `char`, and you’re down to 16. Use `offsetof()` to confirm: `long` at offset 0, `int` at 8, `char` at 12. Total padding? Just 3 bytes. You’ve minimized structure padding and slashed your memory footprint-critical when every byte counts at the address of a struct in embedded systems.

Pack Structures With #Pragma Pack (Use With Care)

Even with well-ordered members, padding can still sneak in and inflate your struct size, so if you’re squeezing every byte on an Arduino or an ARM-based board like the STM32, consider `#pragma pack(1)` to strip out alignment gaps entirely. This directive forces members to align on 1-byte boundaries, eliminating structure padding and helping you reduce memory usage-perfect for tight embedded systems. With `pragma pack`, a struct of `uint16_t`, `uint8_t`, `uint16_t` goes from 6 to 5 bytes, packing data tightly. But watch out: unaligned memory access can slow CPU fetches or trigger exceptions on ARM or SPARC. Use `#pragma pack(pop)` afterward to restore normal padding and packing rules. While it saves space when mapping hardware registers or network packets, misuse risks memory access issues. Always align with care.

Fill Gaps With Bitfields (When Safe)

A single byte can pack more than just one flag when you use bitfields to fill otherwise wasted padding, and that’s exactly how savvy developers squeeze extra efficiency from tight memory budgets on microcontrollers like the Arduino Uno or STM32. You’re likely leaving unused bytes in your structs due to alignment-like 7 bytes of padding after a char before a long on 64-bit systems. Bitfields let you reclaim those gaps, packing flags right into the padding without increasing the total size. They fit neatly between structure members, using the underlying hardware’s word size, and keep data properly aligned. Since the address of its first member remains unchanged, memory footprint shrinks with no runtime cost to pointer logic. Just mind the trade-offs: bitfields can’t cross storage boundaries, and access involves masking-so check your compiler’s behavior. For embedded projects, where every byte counts, bitfields are a smart, safe win.

On a final note

You save memory on Arduino and microcontrollers by reordering struct members from largest to smallest-like placing a 4-byte float before a 1-byte bool-trimming padding fast. Use offsetof) to measure gaps, then confirm savings on an Uno with 2KB RAM. Pragma pack(1) works, but slows access; bitfields help, yet test thoroughly. Real builds on ESP32 show 30% struct size drops, boosting data buffer headroom without cost.

Similar Posts