zig-tipos-datos-primitivos

Primitive Data Types in Zig: Integers, Floats, and Booleans

  • 5 min

The primitive types in Zig are the basic building blocks we use to represent numbers, booleans, and other simple values. If you come from JavaScript or Python, you might be used to a number being simply a Number or an int; in Zig, how many bits it occupies matters.

Zig is a systems language, so size is part of the type.

In Zig, we don’t say “I want a number.” We say: “I want an integer, unsigned, that occupies exactly 8 bits”. This precision allows us to:

  1. Save memory: don’t use 64 bits to store a value that ranges from 0 to 10.
  2. Communicate limits: if you use an 8-bit type, the reader knows that value cannot exceed 255.
  3. Avoid errors: the compiler prevents assigning a constant that doesn’t fit in the chosen type.

Integers

The syntax for integers in Zig is wonderfully logical. It consists of a letter (i or u) followed by the number of bits.

  • i (signed integer): integers with a sign, which can be negative.
  • u (unsigned integer): unsigned integers, from zero upwards.

The most common types

Zig TypeC/C++ EquivalentApproximate RangeCommon Use
u8unsigned char0 to 255Raw bytes, pixels, ASCII characters.
i32int-2 billion to +2 billionGeneral counters, standard math.
u64unsigned long long0 to 18 trillionFile sizes, unique IDs, timestamps.
i8signed char-128 to 127Very small signed numbers.
const lives: u8 = 3;           // Correct, fits in 8 bits
const temperature: i8 = -15;   // Correct, accepts negatives
const balance: i32 = 100000;     // Correct
Copied!

If you try to assign a value that doesn’t fit (e.g.: const a: u8 = 300;), Zig will give you a compile-time error. There are no accidental overflows when assigning constants.

isize and usize: the pointer size

There are two special types whose size depends on the processor architecture (32-bit or 64-bit) where the program runs:

  • usize: An unsigned integer the size of a memory address.
  • isize: A signed integer of the same size.

On a modern computer (64-bit), usize is equivalent to u64. When do we use usize? It is the usual type for indices, lengths, and sizes in memory, because it can represent any position in the process’s address space.

const array = [_]u8{1, 2, 3};
// We use usize to represent the index.
const index: usize = 1; 
const value = array[index];
Copied!

Arbitrarily-sized integers

Unlike C, which offers a limited set of common widths, Zig allows you to directly specify the number of bits for an integer.

Do you need a variable that only holds values from 0 to 3? You can use 2 bits. Are you programming a strange network protocol that uses 7-bit fields?

const color_3_bits: u3 = 7;   // Maximum possible value is 7 (111 in binary)
const flags: u7 = 120;        // A 7-bit integer
const mask: u128 = @as(u128, 1) << 100; // A bit located at position 100
Copied!

This is useful for bit packing in embedded systems, protocols, and drivers.

Floating-point numbers

For numbers with decimals, Zig follows the IEEE-754 standard. Here there is no sign distinction (u or i), they are always f.

  • f32: single precision (commonly equivalent to float in C). It is frequent in 3D graphics and games.
  • f64: double precision (commonly equivalent to double in C). Used when we need more precision or range.
  • f16 and f128: less common types; their performance and support depend on the target.
const pi: f64 = 3.14159265359;
const gravity: f32 = 9.81;
Copied!

Do not use floating-point to represent amounts that must be exact: values like 0.1 do not have an exact binary representation. For money, it is usually preferable to store the minimum unit in an integer. Also, to mix integers and floats at runtime, you will have to convert them explicitly.

Booleans

The bool type in Zig is strict. It can only be true or false.

Unlike C or JavaScript, numbers are not booleans.

// JavaScript (valid)
// if (1) { ... }

// Zig (ERROR)
// if (1) { ... } -> error: expected type 'bool', found 'comptime_int'
Copied!

We must be explicit with the condition:

const amount = 5;
if (amount > 0) { // This returns true, so it is valid
    std.debug.print("There is amount", .{});
}
Copied!

This rule prevents confusing a boolean condition with a number or a pointer.

Numeric literals

Zig offers some syntactic conveniences for writing large numbers:

We can use underscores _ to separate thousands and make the number readable. The compiler ignores them.

const one_million: i32 = 1_000_000;
const hex_bytes: u16 = 0xFF_AA;
const binary: u8 = 0b1111_0000;
Copied!