@mulWithOverflow em Zig — Referência e Exemplos

@mulWithOverflow em Zig

O @mulWithOverflow realiza uma multiplicação e indica se houve overflow. Retorna uma tupla com o resultado (possivelmente truncado) e um bit de overflow. Multiplicação é especialmente propensa a overflow — dois valores que cabem em u32 podem facilmente produzir resultado que não cabe.

Sintaxe

@mulWithOverflow(a: T, b: T) struct { T, u1 }

Parâmetros

  • a (T): Primeiro fator (tipo inteiro).
  • b (T): Segundo fator (mesmo tipo inteiro).

Valor de retorno

Retorna uma tupla struct { T, u1 }:

  • [0] (T): Resultado da multiplicação (truncado se overflow).
  • [1] (u1): 1 se houve overflow, 0 caso contrário.

Exemplos práticos

Exemplo 1: Detecção de overflow na multiplicação

const std = @import("std");

pub fn main() void {
    // Sem overflow
    const r1 = @mulWithOverflow(@as(u8, 10), @as(u8, 20));
    std.debug.print("10 * 20 = {} (overflow: {})\n", .{ r1[0], r1[1] });
    // 10 * 20 = 200 (overflow: 0)

    // Com overflow: 200 * 2 = 400, mas u8 vai até 255
    const r2 = @mulWithOverflow(@as(u8, 200), @as(u8, 2));
    std.debug.print("200 * 2 = {} (overflow: {})\n", .{ r2[0], r2[1] });
    // 200 * 2 = 144 (overflow: 1)  — 400 mod 256 = 144
}

Exemplo 2: Alocação segura (verificar tamanho)

const std = @import("std");

fn alocarMatriz(allocator: std.mem.Allocator, linhas: usize, colunas: usize) ![]f64 {
    // Verificar se linhas * colunas causa overflow
    const total = @mulWithOverflow(linhas, colunas);
    if (total[1] != 0) {
        return error.TamanhoExcessivo;
    }

    return try allocator.alloc(f64, total[0]);
}

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();

    const matriz = try alocarMatriz(gpa.allocator(), 100, 100);
    defer gpa.allocator().free(matriz);

    std.debug.print("Alocado: {} elementos\n", .{matriz.len});
}

Exemplo 3: Conversão de unidades com verificação

const std = @import("std");

fn kbParaBytes(kb: u32) !u32 {
    const resultado = @mulWithOverflow(kb, @as(u32, 1024));
    if (resultado[1] != 0) return error.Overflow;
    return resultado[0];
}

fn mbParaBytes(mb: u32) !u32 {
    const kb = @mulWithOverflow(mb, @as(u32, 1024));
    if (kb[1] != 0) return error.Overflow;
    return kbParaBytes(kb[0]);
}

pub fn main() void {
    const bytes = kbParaBytes(512) catch 0;
    std.debug.print("512 KB = {} bytes\n", .{bytes});

    const grande = mbParaBytes(5000) catch |err| {
        std.debug.print("Erro: {s}\n", .{@errorName(err)});
        return;
    };
    _ = grande;
}

Casos de uso comuns

  1. Alocação de memória: Verificar se N * sizeof(T) não causa overflow antes de alocar.
  2. Conversão de unidades: KB para bytes, minutos para milissegundos, etc.
  3. Cálculos financeiros: Multiplicar valores monetários por quantidades.
  4. Dimensionamento de buffers: Calcular tamanho total de matrizes/grids.

Builtins relacionados

Tutoriais relacionados

Continue aprendendo Zig

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