# `@alignOf`

### `@alignOf`

`@alignOf` asks the Zig compiler for the required memory alignment of a type.

Example:

```zig
const a = @alignOf(u32);
```

This means: “What alignment does `u32` need?”

On many targets, `u32` has alignment `4`. That means a `u32` value should usually start at a memory address divisible by 4.

#### What Alignment Means

Memory is a long sequence of bytes.

Each byte has an address:

```text
address:  0  1  2  3  4  5  6  7
memory:   .  .  .  .  .  .  .  .
```

Some types are easiest for the CPU to read when they start at certain address boundaries.

For example, a `u32` is 4 bytes. Many machines prefer a `u32` to start at an address divisible by 4:

```text
good u32 address: 0, 4, 8, 12, 16, ...
```

That is alignment.

If a type has alignment `4`, then values of that type should start at addresses that are multiples of 4.

#### A Simple Program

```zig
const std = @import("std");

pub fn main() void {
    std.debug.print("u8 alignment:  {}\n", .{@alignOf(u8)});
    std.debug.print("u16 alignment: {}\n", .{@alignOf(u16)});
    std.debug.print("u32 alignment: {}\n", .{@alignOf(u32)});
    std.debug.print("u64 alignment: {}\n", .{@alignOf(u64)});
}
```

Possible output on a common 64-bit target:

```text
u8 alignment:  1
u16 alignment: 2
u32 alignment: 4
u64 alignment: 8
```

These values are target-dependent. Zig can compile for many CPUs and operating systems, so exact alignment can vary.

#### Size and Alignment Are Different

`@sizeOf` and `@alignOf` answer different questions.

```zig
@sizeOf(u32)   // how many bytes it occupies
@alignOf(u32)  // where it should start in memory
```

For `u32`, both are often `4`.

But that is not always true for every type.

A type’s size tells you how much memory it uses.

A type’s alignment tells you what address boundary it needs.

#### Why Alignment Exists

Alignment exists because CPUs do not always read memory one byte at a time.

A CPU often reads memory in chunks. If a value starts at a convenient address, the CPU can read it efficiently.

If a value starts at an inconvenient address, one of three things may happen:

The CPU reads it more slowly.

The CPU requires multiple memory operations.

The CPU rejects the access entirely on some architectures.

Zig cares about alignment because Zig cares about real machine behavior.

#### Struct Alignment

Structs also have alignment.

The alignment of a struct usually depends on the strongest alignment required by its fields.

Example:

```zig
const Point = struct {
    x: i32,
    y: i32,
};
```

Each `i32` usually has alignment `4`, so `Point` usually has alignment `4`.

```zig
const std = @import("std");

const Point = struct {
    x: i32,
    y: i32,
};

pub fn main() void {
    std.debug.print("Point size: {}\n", .{@sizeOf(Point)});
    std.debug.print("Point alignment: {}\n", .{@alignOf(Point)});
}
```

Possible output:

```text
Point size: 8
Point alignment: 4
```

The struct uses 8 bytes, but it needs to start on a 4-byte boundary.

#### Padding Comes from Alignment

In the previous section, we saw that structs may contain padding.

Alignment is the reason.

Example:

```zig
const Example = struct {
    a: u8,
    b: u32,
};
```

The field `a` uses 1 byte.

The field `b` usually wants alignment `4`.

So the compiler may place padding between them:

```text
byte 0: a
byte 1: padding
byte 2: padding
byte 3: padding
byte 4: b
byte 5: b
byte 6: b
byte 7: b
```

This gives the struct a size of 8 bytes on many targets.

You can inspect both size and alignment:

```zig
const std = @import("std");

const Example = struct {
    a: u8,
    b: u32,
};

pub fn main() void {
    std.debug.print("size: {}\n", .{@sizeOf(Example)});
    std.debug.print("alignment: {}\n", .{@alignOf(Example)});
}
```

Possible output:

```text
size: 8
alignment: 4
```

#### Field Order Can Affect Padding

Consider this struct:

```zig
const A = struct {
    a: u8,
    b: u64,
    c: u8,
};
```

Now compare it with this one:

```zig
const B = struct {
    b: u64,
    a: u8,
    c: u8,
};
```

They store the same data, but their memory layout may differ.

`A` may need padding before `b` and also after `c`.

`B` puts the largest field first, so it may need less padding.

```zig
const std = @import("std");

const A = struct {
    a: u8,
    b: u64,
    c: u8,
};

const B = struct {
    b: u64,
    a: u8,
    c: u8,
};

pub fn main() void {
    std.debug.print("A size: {}, alignment: {}\n", .{
        @sizeOf(A),
        @alignOf(A),
    });

    std.debug.print("B size: {}, alignment: {}\n", .{
        @sizeOf(B),
        @alignOf(B),
    });
}
```

Possible output:

```text
A size: 24, alignment: 8
B size: 16, alignment: 8
```

The alignment is the same, but the size is different because the padding is different.

#### Alignment of Pointers

A pointer type also carries alignment information.

Example:

```zig
const p: *u32 = undefined;
```

A `*u32` pointer means: this pointer points to a `u32`, and the address should satisfy the alignment required by `u32`.

That is different from a pointer to bytes:

```zig
const p: *u8 = undefined;
```

A `u8` has alignment `1`, so a `*u8` can point to any byte address.

This matters when converting pointers. Zig will not let you casually treat any byte pointer as a pointer to a more strictly aligned type.

#### Alignment and `@alignCast`

Sometimes you know something about a pointer that Zig cannot prove.

For example, you may receive a byte pointer, but you know it points to memory aligned for `u32`.

Zig provides `@alignCast` for this situation.

A simplified example:

```zig
const bytes: [*]u8 = undefined;
const aligned: [*]align(4) u8 = @alignCast(bytes);
```

This tells Zig: treat this pointer as having 4-byte alignment.

Use this carefully. If the pointer is not actually aligned, the program can fail safety checks or behave incorrectly in unsafe contexts.

For beginners, the main idea is enough: `@alignCast` changes what Zig knows about pointer alignment. It does not magically move the memory.

#### Alignment and C Interop

Alignment matters a lot when Zig talks to C.

C structs have layout and alignment rules. When Zig calls C code or shares data with C, both languages must agree on how data is arranged in memory.

Example:

```zig
const CPoint = extern struct {
    x: c_int,
    y: c_int,
};
```

The `extern struct` tells Zig to use C ABI layout rules.

In this kind of code, `@alignOf` helps you inspect assumptions:

```zig
comptime {
    if (@alignOf(CPoint) != @alignOf(c_int)) {
        @compileError("unexpected CPoint alignment");
    }
}
```

This is useful when building bindings, binary protocols, or system interfaces.

#### Alignment and Packed Structs

Zig also has packed structs.

A packed struct asks Zig to store fields with a compact bit-level layout.

Example:

```zig
const Flags = packed struct {
    read: bool,
    write: bool,
    execute: bool,
};
```

Packed structs are useful for hardware registers, binary formats, and bit fields.

But packed layout changes the usual alignment and padding behavior.

Do not use packed structs just to “save memory” in ordinary application code. Use them when you need an exact representation.

#### Alignment Is Known at Compile Time

Like `@sizeOf`, `@alignOf` is evaluated at compile time.

You can store the result in a constant:

```zig
const alignment = @alignOf(u64);
```

You can use it in compile-time checks:

```zig
comptime {
    if (@alignOf(u64) < 8) {
        @compileError("expected u64 to have at least 8-byte alignment");
    }
}
```

This is useful when your code depends on target-specific assumptions.

#### When Beginners Should Care About Alignment

At the beginning, you do not need to optimize every struct layout.

But you should understand alignment because it explains many Zig behaviors:

Why structs have padding.

Why field order can affect memory use.

Why pointer casts are checked carefully.

Why C interop requires exact layout rules.

Why some low-level memory code needs extra care.

Most normal Zig code does not call `@alignOf` often. But when you work with memory layout, binary formats, allocators, C libraries, SIMD, or hardware, alignment becomes important.

#### Common Mistake: Thinking Alignment Is Size

This is wrong:

```zig
@alignOf(T) == @sizeOf(T)
```

It may be true for some primitive types, but it is not a rule.

Example:

```zig
const S = struct {
    a: u8,
    b: u32,
};
```

On many targets:

```text
@sizeOf(S)  = 8
@alignOf(S) = 4
```

The size is the total number of bytes in the struct.

The alignment is the address boundary required for the struct.

They answer different questions.

#### Common Mistake: Assuming All Targets Are the Same

Zig is a cross-compilation language.

The same source code can target different CPUs and operating systems.

So this kind of assumption can be fragile:

```zig
comptime {
    if (@alignOf(usize) != 8) {
        @compileError("only supports this one layout");
    }
}
```

Sometimes that is exactly what you want. But write such checks only when your program truly requires that target layout.

For portable code, prefer designing around Zig’s type system instead of hard-coding machine assumptions.

#### Key Idea

`@alignOf(T)` returns the memory alignment required by type `T`.

Alignment tells you where a value should start in memory.

It explains padding, struct layout, pointer rules, and many low-level details.

When you use `@alignOf`, you are asking the compiler about the physical layout requirements of a type.

