Integer Truncation — Como Resolver em Zig

Integer Truncation — Como Resolver em Zig

O Que Este Erro Significa

O erro de truncamento de inteiros ocorre quando você tenta converter um valor de um tipo inteiro maior para um tipo menor e o valor não cabe no tipo de destino. Em Zig, essa conversão nunca acontece silenciosamente — o compilador (em comptime) ou o runtime (em debug) detecta que bits significativos seriam perdidos e emite um erro.

Em tempo de compilação:

error: type 'u8' cannot represent the value '300'

Em runtime com @intCast:

thread 1 panic: integer cast truncated bits

Esse comportamento previne bugs sutis que são comuns em C, onde valores são silenciosamente truncados sem aviso.

Causas Comuns

1. Valor Literal Grande Demais para o Tipo

pub fn main() void {
    const x: u8 = 300; // ERRO DE COMPILAÇÃO: 300 > 255 (max u8)
    _ = x;
}

2. @intCast com Valor que Não Cabe

pub fn main() void {
    const a: u32 = 1000;
    const b: u8 = @intCast(a); // PANIC: 1000 não cabe em u8
    _ = b;
}

3. Resultado de Operação Excede o Tipo

pub fn main() void {
    const a: u16 = 50000;
    const b: u16 = 30000;
    const soma: u16 = a + b; // PANIC: 80000 > 65535 (max u16)
    _ = soma;
}

4. Conversão de usize para Tipo Menor

pub fn main() void {
    const tamanho: usize = 1_000_000;
    const indice: u16 = @intCast(tamanho);
    // PANIC em plataformas onde usize > 16 bits
    _ = indice;
}

5. Truncamento em Retorno de Função

fn calcular() u8 {
    var resultado: u32 = 500;
    _ = &resultado;
    return @intCast(resultado); // PANIC: 500 não cabe em u8
}

Como Corrigir

Solucao 1: Usar Tipo Grande o Suficiente

pub fn main() void {
    const x: u16 = 300; // u16 suporta até 65535
    _ = x;
}

Solucao 2: Usar @truncate para Truncamento Explícito

Quando você intencionalmente quer os bits inferiores:

pub fn main() void {
    const a: u32 = 0x12345678;
    const b: u8 = @truncate(a); // b = 0x78 (byte mais baixo)
    _ = b;
}

Solucao 3: Verificar Antes de Converter

const std = @import("std");

pub fn main() void {
    const valor: u32 = 1000;
    if (valor <= std.math.maxInt(u8)) {
        const pequeno: u8 = @intCast(valor);
        std.debug.print("Convertido: {}\n", .{pequeno});
    } else {
        std.debug.print("Valor {} é grande demais para u8\n", .{valor});
    }
}

Solucao 4: Usar std.math.cast (Retorna Optional)

const std = @import("std");

pub fn main() void {
    const valor: u32 = 1000;
    const resultado: ?u8 = std.math.cast(u8, valor);
    if (resultado) |v| {
        std.debug.print("Convertido: {}\n", .{v});
    } else {
        std.debug.print("Não cabe em u8\n", .{});
    }
}

Solucao 5: Usar Saturação (@min/@max)

pub fn main() void {
    const valor: u32 = 1000;
    const saturado: u8 = @intCast(@min(valor, 255)); // Limita a 255
    _ = saturado; // saturado == 255
}

Solucao 6: Usar Operações Saturantes

pub fn main() void {
    const a: u8 = 200;
    const b: u8 = 100;
    const soma = a +| b; // Adição saturante: 255 (não 300)
    _ = soma;
}

@intCast vs @truncate

OperaçãoComportamentoQuando Usar
@intCastPanic se bits são perdidosQuando o valor DEVE caber
@truncateDescarta bits superiores silenciosamenteQuando quer os N bits inferiores
pub fn main() void {
    const x: u16 = 0x1234;

    // @intCast — PANIC porque 0x1234 > 255
    // const a: u8 = @intCast(x);

    // @truncate — retorna 0x34 (byte inferior)
    const b: u8 = @truncate(x); // b == 0x34
    _ = b;
}

Truncamento em Comptime

Em comptime, qualquer truncamento é erro de compilação:

pub fn main() void {
    // Comptime — erro de compilação
    const a: u8 = 256; // ERRO: 256 não cabe em u8

    // Runtime — panic em Debug
    var b: u32 = 256;
    _ = &b;
    const c: u8 = @intCast(b); // PANIC em runtime
    _ = a;
    _ = c;
}

Operações Aritméticas Saturantes

Zig oferece operadores especiais que saturam ao invés de truncar:

pub fn main() void {
    const a: u8 = 250;

    // Operadores padrão — panic em overflow
    // const b = a + 10; // PANIC: 260 > 255

    // Operadores saturantes — limitam ao máximo
    const c = a +| 10; // c == 255
    const d = a *| 2;  // d == 255

    // Operadores wrapping — voltam ao início
    const e = a +% 10; // e == 4 (260 % 256)

    _ = c;
    _ = d;
    _ = e;
}

Erros Relacionados

Continue aprendendo Zig

Explore mais tutoriais e artigos em português para dominar a linguagem Zig.