Zig Data Types

Every value in Zig has a type. The type tells Zig how much memory the value needs, what operations are valid on it, and how to interpret the raw bits stored in that memory. Zig's type system is explicit — you always know the type of every value, either because you wrote it or because Zig inferred it and you can look it up.

Integer Types

Integers hold whole numbers — no decimal point. Zig lets you choose exactly how large an integer is and whether it can be negative.

  Signed integers (can be negative):
  i8   → -128 to 127
  i16  → -32,768 to 32,767
  i32  → -2 billion to 2 billion (approx)
  i64  → very large negative to very large positive
  i128 → astronomically large range

  Unsigned integers (zero and positive only):
  u8   → 0 to 255
  u16  → 0 to 65,535
  u32  → 0 to ~4 billion
  u64  → 0 to ~18 quintillion
  u128 → enormous positive range

Choosing the Right Integer Size

  Question: What are you storing?
       |
  +---------+---------+----------+
  |         |         |          |
  Age     Score    File size  Pixel color
  (0-150) (any)    (bytes)    (0-255)
    |         |         |          |
   u8       i32       u64         u8

Pick the smallest type that fits your data. A person's age never exceeds 150, so u8 works perfectly and uses only 1 byte. Using i64 for an age wastes 7 bytes per value — harmless for one value, significant for a list of a million users.

Special Integer Types

Zig also provides usize and isize. These match the pointer size of the machine — 32 bits on 32-bit systems, 64 bits on 64-bit systems. Use usize for array indices and memory sizes, since these types guarantee compatibility with the machine's addressing capability.

Floating-Point Types

Floating-point numbers store values with a decimal point.

  f16  → Less precision, smaller range (half precision)
  f32  → Single precision (about 7 decimal digits of accuracy)
  f64  → Double precision (about 15 decimal digits) ← Default
  f128 → Quad precision (very high accuracy, slower)
  const pi: f64 = 3.14159265358979;
  const temperature: f32 = 36.6;
  const tiny: f16 = 0.001;

Use f64 for most calculations. Use f32 when memory is tight (common in graphics and embedded systems). Avoid f16 unless you specifically need it — precision is limited.

Boolean Type

A boolean holds exactly one of two values: true or false.

  const is_logged_in: bool = true;
  const has_errors: bool = false;
  Real-world analogy:

  Light switch:
  +---------+
  |   ON    |  ← true
  +---------+

  +---------+
  |   OFF   |  ← false
  +---------+

Booleans drive decisions in your program. If statements, loops, and conditions all work with boolean values.

Character and String Types

Single Characters

A single character uses the type u8. Characters in Zig are just numbers — each character maps to a number in the ASCII or UTF-8 standard.

  const letter: u8 = 'A';
  // 'A' is stored internally as the number 65

Strings

Strings in Zig are sequences of bytes — specifically, a pointer to an array of u8 values followed by a zero terminator.

  const greeting = "Hello";

  Memory layout:
  [ H ][ e ][ l ][ l ][ o ][ 0 ]
   72   101  108  108  111   0
                              ^
                         Null terminator
                         (marks end of string)

The type of a string literal like "Hello" is *const [5:0]u8 — a pointer to a constant array of 5 bytes terminated by zero. This looks complex but the compiler manages it for you in most cases. When writing functions that accept text, use the type []const u8, which is a slice — a pointer plus a length.

Comptime Integers and Floats

  const x = 42;       // Type: comptime_int
  const y = 3.14;     // Type: comptime_float

When Zig infers the type of a number literal without a type annotation, it creates a comptime value. These values exist only during compilation and have arbitrary precision. They convert automatically to whichever concrete type you use them with. This is why you can write const n: u8 = 42 — the comptime_int value 42 fits in a u8, so Zig accepts it.

The void Type

void means "no value." Functions that return nothing have the return type void. You cannot store a void value in a variable because there is nothing to store.

  fn greet() void {
      // Does work but returns nothing
  }

Type Casting

Zig does not automatically convert between numeric types. You must cast explicitly using @as or casting functions:

  const a: i32 = 100;
  const b: i64 = @as(i64, a);  // Explicit widening cast

  const big: i32 = 300;
  const small: u8 = @truncate(big);  // Truncates to 44 (300 mod 256)
  Automatic (allowed)    |    Requires explicit cast
  -----------------------|---------------------------
  comptime_int → i32     |    i64 → i32
  comptime_float → f64   |    f64 → f32
  (literal fits)         |    i32 → u8 (may truncate)

This strictness prevents subtle bugs where a large number silently gets cut down to a smaller type. In Zig, data loss always requires your explicit consent.

Checking Types at Compile Time

Use the built-in @TypeOf to discover the type of any expression:

const std = @import("std");

pub fn main() void {
    const x = 42;
    const y = 3.14;
    std.debug.print("x is {}\n", .{@TypeOf(x)});
    std.debug.print("y is {}\n", .{@TypeOf(y)});
}

Output:

x is comptime_int
y is comptime_float

This tool helps while learning — when you are unsure what type Zig inferred, print it and see.

Type Summary Table

  Category      | Examples          | Use For
  --------------|-------------------|-------------------------
  Signed int    | i8, i32, i64      | Numbers that go negative
  Unsigned int  | u8, u32, u64      | Zero and positive only
  Float         | f32, f64          | Decimal numbers
  Boolean       | bool              | True/false decisions
  Character     | u8 with 'A'       | Single characters
  String        | []const u8        | Text sequences
  Void          | void              | No return value

Leave a Comment

Your email address will not be published. Required fields are marked *