# Pointer Sized Integers

> usize, isize, and why they are not just u64.

```zig
const std = @import("std");
const expect = std.testing.expect;

test "usize matches pointer width" {
    try expect(@sizeOf(usize) == @sizeOf(*u8));
    try expect(@sizeOf(isize) == @sizeOf(*u8));
}

test "usize is the index and length type" {
    // `.len` is a usize, and so is anything used to index a slice.
    const array = [_]u8{ 1, 2, 3 };
    const length: usize = array.len;
    try expect(length == 3);
    try expect(@TypeOf(array.len) == usize);
}

test "wasm32 is a 32-bit target" {
    // These snippets are compiled to wasm32-wasi, so a pointer is 4 bytes.
    // The same source on x86_64 would see 8.
    try expect(@sizeOf(usize) == 4);
}
```

*Runnable: compiled to WebAssembly and executed by CI against Zig master. (`02-language.pointer-sized-integers`)*

`usize` and `isize` are exactly as wide as a pointer on the target. They are
the types of `.len` and of anything used to index a slice.

## They are target-dependent, and that is the point

The snippets on this site compile to `wasm32-wasi`, so `@sizeOf(usize)` is
**4**. Build the identical source for `x86_64` and it is 8. That is why the
last test above asserts 4: it is a fact about the target, not about Zig.

Writing `u64` where you mean `usize` produces code that works on your machine
and breaks on a 32-bit one. Writing `usize` where you mean "a 64-bit counter"
produces code that silently narrows on wasm. The distinction is worth keeping
straight.

## Converting

Integer casts are never implicit when they could lose information, so going
between `usize` and a fixed width is explicit:

```zig
const n: u32 = @intCast(slice.len);   // checked in safety builds
```
