# Alignment

### Alignment

Memory has addresses. Types also have alignment.

The alignment of a type is the address boundary where values of that type are expected to live. An `i32`, for example, is usually stored at an address divisible by 4. A `u64` is usually stored at an address divisible by 8.

Zig exposes alignment as part of the type system.

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

pub fn main() void {
    std.debug.print("{d}\n", .{@alignOf(i32)});
}
```

This prints the alignment of `i32` on the current target.

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

```zig
@alignOf(u8)
@alignOf(u16)
@alignOf(u32)
@alignOf(u64)
```

The exact values depend on the target. On common machines, `u8` has alignment 1, `u16` has alignment 2, `u32` has alignment 4, and `u64` has alignment 8.

A pointer carries alignment information.

```zig
var x: i32 = 10;
const p: *i32 = &x;
```

The type `*i32` means a pointer to an `i32` with the normal alignment for `i32`.

Sometimes a pointer has a weaker alignment.

```zig
const p: *align(1) i32 = @ptrCast(&x);
```

The type `*align(1) i32` means a pointer to an `i32`, but the compiler may assume only byte alignment.

This distinction matters. A CPU may require aligned access. Even when unaligned access is allowed, it may be slower. More importantly, Zig uses alignment to decide which memory accesses are valid.

A pointer with stronger alignment can be used where weaker alignment is expected.

```zig
var x: i32 = 10;

const strong: *i32 = &x;
const weak: *align(1) i32 = strong;
```

This is safe because a normally aligned `i32` pointer also satisfies alignment 1.

The reverse is not automatic.

```zig
const weak: *align(1) i32 = strong;
const strong_again: *i32 = weak; // error
```

The compiler cannot assume that `weak` is aligned enough for `i32`.

To assert stronger alignment, use `@alignCast`.

```zig
const strong_again: *i32 = @alignCast(weak);
```

This says that the address really satisfies the stronger alignment. If safety checks are enabled, Zig can check this at runtime in cases where the value is known only at runtime.

Alignment appears often when working with raw bytes.

```zig
var bytes: [16]u8 = undefined;
const p: *align(1) i32 = @ptrCast(&bytes[0]);
```

A byte array is aligned for bytes. It is not necessarily aligned for `i32`. Reading an `i32` directly from arbitrary byte storage may require an alignment cast, or a safer operation that copies bytes into an aligned value.

The safe way to read structured data from bytes is often to copy.

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

pub fn main() void {
    const bytes = [_]u8{ 1, 0, 0, 0 };
    const value = std.mem.readInt(u32, bytes[0..4], .little);

    std.debug.print("{d}\n", .{value});
}
```

This reads four bytes as a little-endian `u32`. It does not require treating the byte address as a `*u32`.

Packed structs also affect alignment.

```zig
const Header = packed struct {
    tag: u8,
    len: u32,
};
```

In a normal struct, fields may have padding so each field is suitably aligned. In a packed struct, fields are placed more tightly. A field inside a packed struct may not be naturally aligned.

For this reason, taking pointers to fields of packed structs needs care. The pointer may have a smaller alignment than the field type usually has.

Alignment is also important for allocators. An allocator must return memory aligned enough for the type that will be stored there.

```zig
const allocator = std.heap.page_allocator;

const p = try allocator.create(i32);
defer allocator.destroy(p);

p.* = 123;
```

`create(i32)` returns storage suitable for an `i32`. The allocator handles size and alignment.

For arrays, the allocation must be suitable for every element.

```zig
const items = try allocator.alloc(u64, 100);
defer allocator.free(items);
```

The returned slice is aligned for `u64`.

Most programs do not need to mention alignment explicitly. Values, arrays, structs, and allocator calls usually do the right thing.

Alignment becomes visible when code crosses into raw memory: byte buffers, binary formats, hardware registers, packed structs, and C interfaces.

The practical rule is simple: do not pretend that arbitrary bytes are already an aligned value. Either read the bytes explicitly, or prove the alignment and say so with the type.

Exercise 5-21. Print `@alignOf(u8)`, `@alignOf(u16)`, `@alignOf(u32)`, and `@alignOf(u64)`.

Exercise 5-22. Create a byte array and read a `u32` from it using `std.mem.readInt`.

Exercise 5-23. Declare a pointer of type `*align(1) i32` and try to assign it to `*i32`. Read the compiler error.

Exercise 5-24. Use `@alignCast` to convert a weakly aligned pointer back to a normally aligned pointer when the address is valid.

