integer overflow at comptime — Como Resolver em Zig

integer overflow at comptime — Como Resolver em Zig

O Que Este Erro Significa

O erro de integer overflow em tempo de compilação ocorre quando uma operação aritmética realizada durante a compilação produz um resultado que não cabe no tipo inteiro utilizado. Diferente de muitas linguagens que simplesmente “envolvem” o valor (wrap around) silenciosamente, Zig detecta overflow tanto em tempo de compilação quanto em tempo de execução (modo Debug) e o trata como erro.

Em comptime, o Zig é ainda mais rigoroso: como o cálculo acontece durante a compilação, o compilador pode verificar com certeza absoluta que ocorreu overflow e rejeita o código.

Causas Comuns

1. Multiplicação que Excede o Tipo

pub fn main() void {
    const x: u8 = 200;
    const y: u8 = 2;
    const resultado = x * y; // ERRO: 200 * 2 = 400, que não cabe em u8 (max 255)
    _ = resultado;
}

2. Soma que Excede o Limite

pub fn main() void {
    const a: u8 = 250;
    const b: u8 = 10;
    const c = a + b; // ERRO: 250 + 10 = 260, não cabe em u8
    _ = c;
}

3. Subtração com Resultado Negativo em Unsigned

pub fn main() void {
    const x: u32 = 5;
    const y: u32 = 10;
    const diff = x - y; // ERRO: 5 - 10 = -5, não pode ser representado em u32
    _ = diff;
}

4. Shift que Excede o Tamanho

pub fn main() void {
    const x: u8 = 1;
    const resultado = x << 8; // ERRO: shift de 8 bits em u8 (max shift é 7)
    _ = resultado;
}

5. Literal comptime_int que Não Cabe no Tipo Destino

pub fn main() void {
    const x: u8 = 256; // ERRO: 256 não cabe em u8 (range: 0-255)
    _ = x;
}

6. Cálculos em Constantes Globais

const TAMANHO_PAGINA: u16 = 4096;
const NUM_PAGINAS: u16 = 20;
const TOTAL: u16 = TAMANHO_PAGINA * NUM_PAGINAS; // ERRO: 81920 não cabe em u16

Como Corrigir

Solução 1: Usar um Tipo Maior

A solução mais comum é usar um tipo que comporte o resultado:

pub fn main() void {
    const x: u16 = 200; // u16 ao invés de u8
    const y: u16 = 2;
    const resultado = x * y; // OK: 400 cabe em u16
    _ = resultado;
}

Solução 2: Usar Aritmética com @intCast

Quando o resultado intermediário é maior mas o resultado final cabe:

pub fn main() void {
    const x: u8 = 200;
    const y: u8 = 2;
    const temp: u16 = @as(u16, x) * @as(u16, y); // Calcula em u16
    // Se precisar converter de volta para u8, apenas se couber
    _ = temp;
}

Solução 3: Usar Operações Saturantes

Zig oferece operadores com saturação que limitam ao valor máximo/mínimo:

pub fn main() void {
    const x: u8 = 200;
    const y: u8 = 2;
    const resultado = x +| y; // Saturante: resultado máximo é 255
    // +| (soma saturante), -| (subtração saturante), *| (multiplicação saturante)
    _ = resultado;
}

Solução 4: Usar Operações com Wrap (Envolvimento)

Se o comportamento de wrap-around é o desejado:

pub fn main() void {
    const x: u8 = 200;
    const y: u8 = 100;
    const resultado = x +% y; // Wrap: (200 + 100) % 256 = 44
    // +% (soma com wrap), -% (subtração com wrap), *% (multiplicação com wrap)
    _ = resultado;
}

Solução 5: Verificar Antes de Operar

const std = @import("std");

pub fn main() void {
    const x: u8 = 200;
    const y: u8 = 100;
    const resultado = @addWithOverflow(x, y);
    if (resultado[1] != 0) {
        std.debug.print("overflow detectado!\n", .{});
    } else {
        std.debug.print("resultado: {}\n", .{resultado[0]});
    }
}

Solução 6: Corrigir Constantes Globais

const TAMANHO_PAGINA: u32 = 4096; // u32 ao invés de u16
const NUM_PAGINAS: u32 = 20;
const TOTAL: u32 = TAMANHO_PAGINA * NUM_PAGINAS; // OK: 81920 cabe em u32

Tabela de Referência: Limites dos Tipos Inteiros

TipoMínimoMáximo
u80255
u16065,535
u3204,294,967,295
u64018.4 quintilhões
i8-128127
i16-32,76832,767
i32-2,147,483,6482,147,483,647

Operadores Aritméticos Especiais do Zig

OperadorTipoDescrição
+NormalErro em overflow (Debug) / UB (Release)
+%WrappingEnvolve ao estourar
`+`Saturating

Erros Relacionados

Continue aprendendo Zig

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