Skip to Content
Course content

66: Structure Padding and Alignment

Click on the "Edit" button in the top corner of the screen to edit your slide content.

You've probably spent the last few lessons getting comfortable with structs, and at this point, you likely view them as simple containers. If you put a 1-byte char and a 4-byte int into a struct, it seems only logical that the struct would take up 5 bytes of memory. It's basic addition, right?

The "Simple Addition" Fallacy

I see this mistake constantly. Learners assume that sizeof(struct) is always exactly the sum of its members. Let's prove why that's not the case with a quick example. Consider this snippet:

struct DeviceStatus {
    char is_active;    // 1 byte
    int error_code;    // 4 bytes
};

printf("Size: %zu\n", sizeof(struct DeviceStatus));

If you run this on a standard 64-bit system, you aren't going to see "5". You're going to see "8". You might think your compiler is broken or that there's some weird overhead to creating a struct, but the reality is more intentional. The compiler has silently inserted 3 bytes of "padding" between is_active and error_code.

The Hidden Tax: Alignment and Padding

Why the waste? It comes down to how your CPU actually talks to your RAM. Most modern processors don't like reading data from arbitrary memory addresses. They are optimized to read data from addresses that are multiples of the data's own size. This is called alignment.

An int (usually 4 bytes) is most efficiently read when its address is a multiple of 4. If the compiler placed the int immediately after the 1-byte char, the int would start at offset 1—which is not a multiple of 4. The CPU would then have to do two memory reads and some bit-shifting to "stitch" the integer together, which kills performance. To avoid this, the compiler inserts padding bytes to ensure the int starts at offset 4.

I'll give you a tip: the struct's overall alignment is determined by its largest member. If you have a double (8 bytes) in your struct, the entire struct will be padded so that its total size is a multiple of 8. This ensures that if you create an array of these structs, every single element in that array remains properly aligned.

Rearranging for Efficiency

Now, here is the part where you can actually control this. While you can't easily tell the compiler "don't pad this" (though #pragma pack exists, I generally advise against it unless you're writing a network driver), you can minimize the waste by ordering your members from largest to smallest.

Look at the difference here:

// Wasteful layout: 12 bytes
struct BadLayout {
    char a;     // 1 byte + 3 padding
    int b;      // 4 bytes
    char c;     // 1 byte + 3 padding
};

// Optimized layout: 8 bytes
struct GoodLayout {
    int b;      // 4 bytes
    char a;     // 1 byte
    char c;     // 1 byte + 2 padding
};

By grouping the smaller types together at the end, we reduced the padding from 6 bytes down to 2. In a small program, this doesn't matter. But if you're allocating an array of a million BadLayout structs, you're wasting 4 megabytes of RAM for absolutely no reason. That's the kind of detail that separates a hobbyist from a professional engineer.




📋 Practical Task

The Struct Packing Audit

Your goal is to write a program that demonstrates your understanding of alignment by creating a "memory-waste" report.

  1. Define a struct called NetworkPacket that contains the following members in this exact order: char version, int packet_id, char flags, and double timestamp.
  2. Define a second struct called OptimizedPacket containing the exact same members, but reordered to minimize padding.
  3. In your main function, use sizeof() to print the size of both structs.
  4. Calculate and print the number of bytes wasted in the NetworkPacket compared to the OptimizedPacket.
  5. As an extra challenge, use the & (address-of) operator to print the memory addresses of the members within the NetworkPacket struct to prove that the int and double are starting on aligned boundaries.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.