Como Converter entre Bases Numéricas em Zig

Introdução

Converter números entre diferentes bases numéricas (decimal, binário, hexadecimal, octal) é uma operação frequente em programação de sistemas, protocolos de rede e manipulação de dados de baixo nível. Zig facilita essas conversões com formatação e parsing integrados.

Nesta receita, você aprenderá a converter números entre bases de forma prática e eficiente.

Pré-requisitos

Converter Número para Diferentes Bases

Use formatadores de std.fmt para exibir números em diferentes bases:

const std = @import("std");

pub fn main() !void {
    const numero: u32 = 255;

    std.debug.print("Número: {d}\n\n", .{numero});
    std.debug.print("Decimal:     {d}\n", .{numero});
    std.debug.print("Binário:     {b}\n", .{numero});
    std.debug.print("Octal:       {o}\n", .{numero});
    std.debug.print("Hexadecimal: {x}\n", .{numero});
    std.debug.print("Hex maiúsc.: {X}\n", .{numero});

    // Com padding e prefixo
    std.debug.print("\nCom formatação:\n", .{});
    std.debug.print("Binário 8 bits:  {b:0>8}\n", .{numero});
    std.debug.print("Binário 16 bits: {b:0>16}\n", .{numero});
    std.debug.print("Hex 2 dígitos:   {X:0>2}\n", .{numero});
    std.debug.print("Hex 4 dígitos:   {X:0>4}\n", .{numero});
    std.debug.print("Hex 8 dígitos:   {X:0>8}\n", .{numero});
}

Saída esperada

Número: 255

Decimal:     255
Binário:     11111111
Octal:       377
Hexadecimal: ff
Hex maiúsc.: FF

Com formatação:
Binário 8 bits:  11111111
Binário 16 bits: 0000000011111111
Hex 2 dígitos:   FF
Hex 4 dígitos:   00FF
Hex 8 dígitos:   000000FF

Converter Strings para Números em Diferentes Bases

const std = @import("std");

pub fn main() !void {
    // Parsear string hexadecimal
    const hex_str = "FF";
    const valor_hex = try std.fmt.parseInt(u32, hex_str, 16);
    std.debug.print("Hex \"{s}\" = {d}\n", .{ hex_str, valor_hex });

    // Parsear string binária
    const bin_str = "11001010";
    const valor_bin = try std.fmt.parseInt(u32, bin_str, 2);
    std.debug.print("Bin \"{s}\" = {d}\n", .{ bin_str, valor_bin });

    // Parsear string octal
    const oct_str = "377";
    const valor_oct = try std.fmt.parseInt(u32, oct_str, 8);
    std.debug.print("Oct \"{s}\" = {d}\n", .{ oct_str, valor_oct });

    // Parsear decimal
    const dec_str = "42";
    const valor_dec = try std.fmt.parseInt(u32, dec_str, 10);
    std.debug.print("Dec \"{s}\" = {d}\n", .{ dec_str, valor_dec });

    // Auto-detectar base (0x para hex, 0o para octal, 0b para binário)
    const auto_hex = try std.fmt.parseInt(u32, "0xFF", 0);
    const auto_bin = try std.fmt.parseInt(u32, "0b1010", 0);
    const auto_oct = try std.fmt.parseInt(u32, "0o77", 0);
    std.debug.print("\nAuto-detecção:\n", .{});
    std.debug.print("0xFF = {d}\n", .{auto_hex});
    std.debug.print("0b1010 = {d}\n", .{auto_bin});
    std.debug.print("0o77 = {d}\n", .{auto_oct});
}

Tabela de Conversão

const std = @import("std");

pub fn main() !void {
    std.debug.print("{s:>5} {s:>10} {s:>5} {s:>8}\n", .{ "Dec", "Bin", "Oct", "Hex" });
    std.debug.print("{s:>5} {s:>10} {s:>5} {s:>8}\n", .{ "---", "---", "---", "---" });

    const valores = [_]u8{ 0, 1, 7, 8, 10, 15, 16, 42, 100, 127, 255 };
    for (&valores) |v| {
        std.debug.print("{d:>5} {b:0>8} {o:>5} {X:0>2}\n", .{ v, v, v, v });
    }
}

Converter Número para String em Base Específica

const std = @import("std");

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

    const numero: u32 = 12345;

    // Converter para string hexadecimal
    const hex = try std.fmt.allocPrint(allocator, "{X}", .{numero});
    defer allocator.free(hex);

    // Converter para string binária
    const bin = try std.fmt.allocPrint(allocator, "{b}", .{numero});
    defer allocator.free(bin);

    // Converter para string octal
    const oct = try std.fmt.allocPrint(allocator, "{o}", .{numero});
    defer allocator.free(oct);

    std.debug.print("{d} em hex: {s}\n", .{ numero, hex });
    std.debug.print("{d} em bin: {s}\n", .{ numero, bin });
    std.debug.print("{d} em oct: {s}\n", .{ numero, oct });

    // Com buffer fixo (sem alocação)
    var buf: [64]u8 = undefined;
    const resultado = try std.fmt.bufPrint(&buf, "0x{X:0>8}", .{numero});
    std.debug.print("Formatado: {s}\n", .{resultado});
}

Manipulação de Bits

const std = @import("std");

pub fn main() !void {
    const valor: u8 = 0b10110011;

    std.debug.print("Valor: {b:0>8} ({d})\n\n", .{ valor, valor });

    // Operações bit a bit
    std.debug.print("NOT:       {b:0>8}\n", .{~valor});
    std.debug.print("AND 0x0F:  {b:0>8}\n", .{valor & 0x0F});
    std.debug.print("OR  0x0F:  {b:0>8}\n", .{valor | 0x0F});
    std.debug.print("XOR 0xFF:  {b:0>8}\n", .{valor ^ 0xFF});
    std.debug.print("Shift L 2: {b:0>8}\n", .{@as(u8, valor << 2)});
    std.debug.print("Shift R 2: {b:0>8}\n", .{valor >> 2});

    // Contar bits
    std.debug.print("\nBits em 1: {d}\n", .{@popCount(valor)});
    std.debug.print("Zeros à esquerda: {d}\n", .{@clz(valor)});
    std.debug.print("Zeros à direita: {d}\n", .{@ctz(valor)});
}

Dicas e Boas Práticas

  1. Literais numéricos em Zig: Use 0x para hex, 0o para octal, 0b para binário diretamente no código.

  2. std.fmt.parseInt com base 0: Auto-detecta a base pelo prefixo da string.

  3. Formatadores: {b} binário, {o} octal, {x} hex minúsculo, {X} hex maiúsculo.

  4. Padding: {X:0>8} formata com zeros à esquerda em 8 dígitos.

Receitas Relacionadas

Tutoriais Relacionados

Continue aprendendo Zig

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