# `@sizeOf`

### `@sizeOf`

`@sizeOf` asks the Zig compiler how many bytes a type needs in memory.

Example:

```zig
const n = @sizeOf(u32);
```

For `u32`, the result is `4`, because a 32-bit unsigned integer uses 4 bytes.

A byte is 8 bits. So:

```text
u8   = 1 byte
u16  = 2 bytes
u32  = 4 bytes
u64  = 8 bytes
```

The name `@sizeOf` means “size of this type.”

#### `@sizeOf` Takes a Type

`@sizeOf` does not ask for the size of a value directly. It asks for the size of a type.

This is correct:

```zig
const a = @sizeOf(u64);
```

This is also common:

```zig
const x: i32 = 123;
const b = @sizeOf(@TypeOf(x));
```

Here, `@TypeOf(x)` gets the type of `x`, which is `i32`. Then `@sizeOf(i32)` returns the size of that type.

You can read it like this:

```text
What is the type of x?
What is the size of that type?
```

#### A Simple Program

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

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

Possible output:

```text
u8:  1 byte
u16: 2 bytes
u32: 4 bytes
u64: 8 bytes
```

These sizes matter because Zig is a systems programming language. You often need to know exactly how much memory your data uses.

#### Why Size Matters

Memory is not abstract in Zig. Your data has a real layout.

If you store one million `u64` values, each value uses 8 bytes.

So the total memory for the raw values is:

```text
1,000,000 * 8 = 8,000,000 bytes
```

That is about 8 megabytes, before considering allocator overhead or container metadata.

If you used `u32` instead:

```text
1,000,000 * 4 = 4,000,000 bytes
```

That is about 4 megabytes.

Choosing the right type can cut memory use in half.

#### Struct Sizes

`@sizeOf` is especially useful with structs.

Example:

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

const size = @sizeOf(Point);
```

Each `i32` uses 4 bytes. The struct has two of them. So `Point` is usually 8 bytes.

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

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

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

Possible output:

```text
Point size: 8 bytes
```

#### Padding

Struct size is not always just the sum of field sizes.

The compiler may add padding bytes to keep fields aligned correctly.

Example:

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

`u8` is 1 byte. `u32` is 4 bytes.

A beginner may expect:

```text
1 + 4 = 5 bytes
```

But the actual size is usually larger, often 8 bytes.

Why? Because `u32` usually wants to start at an address aligned to 4 bytes. The compiler may insert 3 padding bytes after `a`.

The memory layout may look like this:

```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
```

So:

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

const size = @sizeOf(Example); // often 8
```

Padding is normal. It helps the CPU read values efficiently.

#### Field Order Can Change Size

The order of fields can affect struct size.

Compare these two structs:

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

and:

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

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

`A` may need more padding than `B`.

You can inspect this:

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

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

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

pub fn main() void {
    std.debug.print("A: {} bytes\n", .{@sizeOf(A)});
    std.debug.print("B: {} bytes\n", .{@sizeOf(B)});
}
```

Possible output:

```text
A: 12 bytes
B: 8 bytes
```

This is one reason systems programmers care about layout.

#### Arrays

For arrays, `@sizeOf` includes every element.

```zig
const Numbers = [4]u32;
const size = @sizeOf(Numbers);
```

A `u32` is 4 bytes. The array has 4 elements.

So the size is:

```text
4 * 4 = 16 bytes
```

Example:

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

pub fn main() void {
    std.debug.print("[4]u32 size: {} bytes\n", .{@sizeOf([4]u32)});
}
```

Output:

```text
[4]u32 size: 16 bytes
```

A fixed array stores its elements directly. The array value contains the actual elements.

#### Slices

A slice is different from an array.

A slice points to existing memory and stores a length.

Example type:

```zig
[]u8
```

A slice does not contain all the bytes directly. It contains:

```text
pointer to data
length
```

So `@sizeOf([]u8)` gives the size of the slice header, not the size of the data it points to.

On a 64-bit target, this is commonly 16 bytes:

```text
8-byte pointer + 8-byte length = 16 bytes
```

Example:

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

pub fn main() void {
    std.debug.print("[]u8 size: {} bytes\n", .{@sizeOf([]u8)});
}
```

Possible output on a 64-bit system:

```text
[]u8 size: 16 bytes
```

This does not mean the string or buffer has only 16 bytes of content. It means the slice value itself is 16 bytes.

#### Pointers

Pointer sizes depend on the target.

On a 64-bit target, a pointer is usually 8 bytes.

On a 32-bit target, a pointer is usually 4 bytes.

Example:

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

pub fn main() void {
    std.debug.print("*u8 size: {} bytes\n", .{@sizeOf(*u8)});
}
```

Possible output on a 64-bit system:

```text
*u8 size: 8 bytes
```

This is why `@sizeOf` is target-aware. Zig can cross-compile, and some sizes change depending on the target.

#### `usize`

The type `usize` is an unsigned integer large enough to hold a memory address size for the target.

On a 64-bit target:

```text
@sizeOf(usize) = 8
```

On a 32-bit target:

```text
@sizeOf(usize) = 4
```

This is why `usize` is often used for indexes, lengths, and sizes.

Example:

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

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

#### Zero-Sized Types

Some types have size `0`.

Example:

```zig
const Empty = struct {};
```

This struct has no fields. It stores no data.

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

const Empty = struct {};

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

Output:

```text
Empty size: 0 bytes
```

Zero-sized types are useful in generic code and marker types.

#### Size vs Length

Do not confuse size with length.

For an array:

```zig
const a = [_]u8{ 10, 20, 30 };
```

The length is `3`.

The size is `3` bytes, because each `u8` is 1 byte.

But for this array:

```zig
const b = [_]u32{ 10, 20, 30 };
```

The length is still `3`.

The size is `12` bytes, because each `u32` is 4 bytes.

So:

```text
length = number of elements
size   = number of bytes
```

For arrays, the relationship is:

```text
size = length * size of each element
```

#### A Useful Pattern

You can use `@sizeOf` when allocating memory, checking formats, or validating assumptions.

Example:

```zig
comptime {
    if (@sizeOf(u64) != 8) {
        @compileError("expected u64 to be 8 bytes");
    }
}
```

This check runs at compile time.

For fixed binary formats, this kind of check can prevent subtle bugs.

#### When Beginners Should Use `@sizeOf`

Use `@sizeOf` when you need to know the memory size of a type.

Common cases:

- inspecting structs
- working with binary files
- writing network protocols
- using allocators
- calling C code
- checking pointer and integer sizes
- understanding memory layout

Do not use it to ask how many items are in a slice or array. For that, use `.len`.

Example:

```zig
const xs = [_]u8{ 1, 2, 3 };

const length = xs.len;        // 3
const size = @sizeOf(@TypeOf(xs)); // 3
```

For `u8`, the numbers happen to match. For other types, they may not.

```zig
const ys = [_]u32{ 1, 2, 3 };

const length = ys.len;             // 3
const size = @sizeOf(@TypeOf(ys)); // 12
```

#### Key Idea

`@sizeOf(T)` returns the number of bytes needed to store a value of type `T`.

It is known at compile time.

It is useful because Zig makes memory layout visible. When you understand size, you understand one of the most basic facts about how your program uses memory.

