# Packed Structs

### Packed Structs

A normal Zig struct is designed for ordinary data modeling.

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

This is the right choice most of the time. You define fields, create values, pass them to functions, and access fields by name.

A packed struct has a different purpose.

A `packed struct` gives you tighter control over how fields are stored in memory. It is mainly used when you need to describe data at the bit level.

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

This struct represents three boolean flags. In a normal struct, each `bool` may take more space than one bit because the compiler chooses a layout that is convenient for the target. In a packed struct, Zig packs the fields more tightly.

Packed structs are useful for things like file formats, network protocols, CPU registers, binary headers, and bit flags.

#### Why Normal Structs Are Usually Better

A normal struct lets the compiler choose a good memory layout.

```zig
const User = struct {
    id: u64,
    active: bool,
    score: u32,
};
```

The compiler may add padding between fields. Padding is unused space inserted so that fields can be aligned efficiently in memory.

For beginner code, this is good. You get simple field access and efficient ordinary behavior.

A packed struct tells Zig: layout matters here.

That is a stronger promise. Use it only when the exact representation is part of the problem.

#### A Simple Packed Struct

Here is a small example:

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

You can create a value like this:

```zig
const flags = Flags{
    .read = true,
    .write = false,
    .execute = true,
};
```

You can access fields normally:

```zig
if (flags.read) {
    // reading is allowed
}
```

The syntax looks almost the same as a normal struct. The important difference is the word `packed`.

```zig
packed struct {
    // fields
}
```

That word changes the representation.

#### Packed Structs Are About Representation

Consider this value:

```zig
const flags = Flags{
    .read = true,
    .write = false,
    .execute = true,
};
```

Conceptually, this is three yes-or-no values.

```text
read    = true
write   = false
execute = true
```

As bits, you can think of it like this:

```text
read write execute
  1     0      1
```

Packed structs let you describe that kind of layout directly in Zig code.

This is useful when the bits are not just an implementation detail. Sometimes the bits are the data format.

#### Integer Fields in Packed Structs

Packed structs often use small integer fields.

```zig
const Header = packed struct {
    version: u4,
    kind: u4,
};
```

Here, `u4` means an unsigned 4-bit integer.

The whole struct can fit into 8 bits:

```text
version: 4 bits
kind:    4 bits
```

Example:

```zig
const header = Header{
    .version = 1,
    .kind = 9,
};
```

This is useful when a byte is split into several smaller fields.

In ordinary code, you usually use integer types like `u8`, `u16`, `u32`, and `usize`.

In packed binary layouts, smaller integer widths like `u1`, `u2`, `u3`, or `u4` can be useful.

#### Example: A Byte Split into Fields

Suppose one byte stores two pieces of information:

```text
high 4 bits: version
low 4 bits:  kind
```

We can model that with a packed struct:

```zig
const Header = packed struct {
    kind: u4,
    version: u4,
};
```

Now a single value has named fields:

```zig
const h = Header{
    .kind = 2,
    .version = 1,
};
```

Instead of writing bit masks everywhere, you can write:

```zig
const k = h.kind;
const v = h.version;
```

This makes the program easier to read.

The exact bit order can matter when communicating with external formats. When you write code for a real binary format, read Zig’s rules and the format specification carefully. Do not guess.

#### Boolean Fields

A boolean field in a packed struct can be used as a single flag.

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

This gives names to individual permission bits.

Example:

```zig
const p = Permissions{
    .read = true,
    .write = true,
    .execute = false,
};
```

This is easier to read than using raw numbers:

```zig
const p = 0b011;
```

The raw number is compact, but it does not explain itself. The packed struct gives each bit a name.

#### Packed Structs and Bit Flags

Packed structs are a good fit when you would otherwise write code like this:

```zig
const READ: u8 = 0b001;
const WRITE: u8 = 0b010;
const EXECUTE: u8 = 0b100;
```

With bit masks, checking a flag looks like this:

```zig
const can_read = (flags & READ) != 0;
```

With a packed struct, the idea is named directly:

```zig
const can_read = permissions.read;
```

Both approaches can be useful. Bit masks are common and portable. Packed structs can make the code clearer when you control the layout and understand the representation.

#### Packed Structs Are Not Classes

A packed struct is still a struct.

It can have fields. It can have declarations. It can have methods.

```zig
const Permissions = packed struct {
    read: bool,
    write: bool,
    execute: bool,

    fn canExecute(self: Permissions) bool {
        return self.execute;
    }
};
```

Use it like this:

```zig
const p = Permissions{
    .read = true,
    .write = false,
    .execute = true,
};

const ok = p.canExecute();
```

The method rules are the same as normal structs.

The packed part changes the data layout, not the basic idea of struct methods.

#### When Packed Structs Are Useful

Use packed structs when you are modeling data whose bit layout matters.

Common cases include:

| Use case | Why packed structs help |
|---|---|
| Hardware registers | Each bit or group of bits may control a device feature |
| Binary file formats | Fields may be stored in fixed bit positions |
| Network packets | Headers often contain compact fields |
| Permission flags | Several booleans can fit into one small value |
| Embedded systems | Memory layout and size may be critical |

For ordinary application data, use a normal struct.

#### Be Careful with External Data

Packed structs are tempting when reading binary data.

For example, you may want to map bytes directly to a packed struct. Be careful.

External data can involve:

| Issue | Meaning |
|---|---|
| Endianness | Byte order may differ between systems |
| Alignment | Some addresses may not be safe for direct access |
| Format versions | The layout may change over time |
| Invalid values | The bytes may not represent a valid Zig value |

For serious binary parsing, do not simply cast arbitrary bytes and hope they are valid. Parse carefully, check the data, and handle errors.

Packed structs are a tool. They do not remove the need to validate input.

#### Normal, Extern, and Packed Structs

Zig gives you several struct layout choices.

| Form | Main purpose |
|---|---|
| `struct` | Ordinary Zig data |
| `extern struct` | Match C ABI layout |
| `packed struct` | Control compact bit-level layout |

Use `struct` by default.

Use `extern struct` when you must match C.

Use `packed struct` when you must describe compact binary layout.

This distinction matters. The three forms solve different problems.

#### A Small Practical Example

Suppose we want to describe three feature flags:

```zig
const FeatureFlags = packed struct {
    logging: bool,
    metrics: bool,
    tracing: bool,
};
```

We can use it in a config struct:

```zig
const Config = struct {
    flags: FeatureFlags,
};

const config = Config{
    .flags = FeatureFlags{
        .logging = true,
        .metrics = false,
        .tracing = true,
    },
};
```

Now the code reads clearly:

```zig
if (config.flags.logging) {
    // enable logging
}

if (config.flags.tracing) {
    // enable tracing
}
```

The field names explain the meaning of each bit.

#### The Main Idea

A packed struct is a struct with a compact, layout-focused representation.

Use it when the exact bits matter:

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

Do not use packed structs just because they look efficient. Start with normal structs. Reach for packed structs when you are working with binary layouts, hardware registers, protocol fields, or compact flags where representation is part of the design.

