C Mastery / Structs: Declaration, Access, Padding, Alignment
Part 1 — The Core Language

Structs: Declaration, Access, Padding, Alignment

This chapter introduces struct, C's mechanism for grouping related values into a single object, and explains the padding and alignment rules that determine how structs are laid out in memory.

Why This Matters

Structs are the foundation of every nontrivial C program. Padding and alignment decide sizeof(struct), affect performance, and matter enormously for binary compatibility, file formats, network protocols, and FFI.

Prerequisites

Core Concept

What a struct is

A struct is a composite object type containing a sequence of named members. Each member has its own type and storage.

struct Point {
    int x;
    int y;
};

struct Point is a type; struct Point p; declares an object of that type.

Member access

struct Point p;
p.x = 1;
p.y = 2;

struct Point *q = &p;
q->x = 3;    /* equivalent to (*q).x */

The . operator accesses a member of a struct; -> accesses a member through a pointer.

Padding and alignment

Each type has an alignment requirement (a power of two, typically). A struct's members are laid out in declaration order, and the compiler inserts padding between members (and possibly after the last member) so that each member is properly aligned. The struct's own alignment is the maximum of its members' alignments.

struct Example {
    char c;    /* 1 byte */
    int  i;    /* 4 bytes, must be 4-aligned -> 3 bytes padding before */
};
/* sizeof(struct Example) is 8 on typical systems */

Syntax

Declaration and definition

struct Name {
    type member1;
    type member2;
};

struct Name object;
struct Name *ptr = &object;

Initialization

struct Point p = {1, 2};                 /* positional */
struct Point q = {.x = 1, .y = 2};      /* designated (C99) */

Anonymous struct (C11)

struct Outer {
    int a;
    struct { int b; int c; };   /* anonymous struct member */
};

Members of an anonymous struct are accessed as if they were members of the enclosing struct (o.b, not o.inner.b).

Examples

Struct with padding

#include <stdio.h>
#include <stddef.h>

struct S {
    char c;
    int  i;
};

int main(void)
{
    printf("sizeof(struct S) = %zu\n", sizeof(struct S));
    printf("offsetof(struct S, c) = %zu\n", offsetof(struct S, c));
    printf("offsetof(struct S, i) = %zu\n", offsetof(struct S, i));
    return 0;
}

Expected output (typical LP64):

sizeof(struct S) = 8
offsetof(struct S, c) = 0
offsetof(struct S, i) = 4

offsetof is defined in <stddef.h>.

Copying and returning structs

struct Point a = {1, 2};
struct Point b = a;   /* whole-struct copy */

Structs can be assigned, passed by value, and returned by value. The entire struct (including padding, in the abstract machine) is copied.

How It Works

The compiler assigns each member an offset that is a multiple of the member's alignment. It inserts padding bytes where necessary. The struct size is rounded up to a multiple of the struct's alignment so that arrays of the struct keep each element aligned.

Variations

Packing

Compilers offer pragmas or attributes to pack structs (remove padding):

/* GCC/Clang */
struct __attribute__((packed)) S {
    char c;
    int  i;
};

Packed structs remove padding but can create misaligned accesses (slower, and UB if dereferenced through a misaligned pointer). Use only for file/network/register layouts where the format is fixed. COMPILER-SPECIFIC

Flexible array members (later)

c.struct.fam covers structs whose last member is an array of unspecified size.

Opaque structs (later)

c.struct.decl introduces forward declarations; opaque structs are covered with multi-file programs in c.core.39.

Common Mistakes

this).

with padding inserted).

dereferencing it.

Undefined Behavior

aliasing). VERIFIED

VERIFIED

Portability

Under the Hood

Struct layout is computed by the compiler and baked into every member access as an offset. Member access p->x compiles to a load/store at p + offsetof(T, x). Padding bytes are not read or written by normal member access, though whole-struct copy copies them in the abstract machine.

Practical Usage

serialization for portable data exchange.

Exercises

1. Define a struct with mixed member sizes and print sizeof and each offsetof. Explain every padding byte. 2. Write a function that copies a struct by value and verify it works. 3. Demonstrate -> vs . access. 4. Use a packed struct and observe the change in sizeof (and any warnings).

Deep Challenge

Given this struct, compute sizeof, each member offset, and the total padding on a typical LP64 system, and explain your reasoning:

struct Mixed {
    char a;
    double b;
    char c;
    int d;
};

Then verify with offsetof and sizeof.

References

(stddef.h offsetof).

Verification

verified.`

Progress

Concept checkboxes

Mastery levels

ConceptCurrent level (0–8)Target level
c.struct.decl06
c.struct.padding06
c.struct.alignment06