@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):1se houve overflow,0caso 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
- Alocação de memória: Verificar se N * sizeof(T) não causa overflow antes de alocar.
- Conversão de unidades: KB para bytes, minutos para milissegundos, etc.
- Cálculos financeiros: Multiplicar valores monetários por quantidades.
- Dimensionamento de buffers: Calcular tamanho total de matrizes/grids.
Builtins relacionados
- @addWithOverflow — Adição com detecção de overflow
- @subWithOverflow — Subtração com detecção de overflow
- @shlExact — Shift left exato (multiplicação por potência de 2)
- @min / @max — Limitar valores