---
title: "Substituir Macros C por Comptime Zig"
url: "https://ziglang.com.br/tutoriais/substituir-macros-c-por-comptime-zig/"
markdown_url: "https://ziglang.com.br/tutoriais/substituir-macros-c-por-comptime-zig.MD"
description: "Guia prático para substituir macros do preprocessador C por comptime de Zig. Constantes, macros de função, compilação condicional, header guards e X-macros convertidos para Zig idiomático."
date: "2026-02-21"
author: "Zig Brasil"
---

# Substituir Macros C por Comptime Zig

Guia prático para substituir macros do preprocessador C por comptime de Zig. Constantes, macros de função, compilação condicional, header guards e X-macros convertidos para Zig idiomático.


## Introdução

O preprocessador C é uma das fontes mais comuns de bugs sutis em projetos C. Macros operam por substituição textual, sem type checking, sem escopo, e com efeitos colaterais difíceis de prever. Zig substitui todo o preprocessador por `comptime` — código Zig normal executado em tempo de compilação.

Este guia converte os padrões mais comuns de macros C para equivalentes Zig. Para metaprogramação avançada, veja [Comptime em Zig](/tutoriais/comptime-em-zig/) e [Comptime e Reflection](/tutoriais/zig-comptime-reflection/).

## Pré-requisitos

- Zig instalado (versão 0.13+). Veja [Como Instalar Zig](/tutoriais/como-instalar-zig/)
- Conhecimento do preprocessador C
- Familiaridade com Zig. Consulte [Introdução ao Zig](/tutoriais/introducao-ao-zig/)

## Constantes #define

### C

```c
#define MAX_BUFFER 4096
#define PI 3.14159265358979
#define VERSAO "1.2.3"
#define DEBUG_MODE 1
```

### Zig

```zig
const MAX_BUFFER: usize = 4096;
const PI: f64 = 3.14159265358979;
const VERSAO: []const u8 = "1.2.3";
const DEBUG_MODE: bool = true;
```

Vantagem: constantes Zig têm tipo, são verificadas pelo compilador, e aparecem no debugger.

## Macros de Função

### Macro simples

```c
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define ABS(x) ((x) < 0 ? -(x) : (x))

// Bug clássico:
int resultado = MIN(i++, j++); // i++ ou j++ avaliado DUAS vezes!
```

```zig
fn min(a: anytype, b: @TypeOf(a)) @TypeOf(a) {
    return if (a < b) a else b;
}

fn max(a: anytype, b: @TypeOf(a)) @TypeOf(a) {
    return if (a > b) a else b;
}

fn abs(x: anytype) @TypeOf(x) {
    return if (x < 0) -x else x;
}

// Sem bug: argumentos avaliados UMA vez
var i: i32 = 5;
var j: i32 = 10;
const resultado = min(blk: { i += 1; break :blk i; }, blk: { j += 1; break :blk j; });
```

### ARRAY_SIZE

```c
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))

int numeros[] = {1, 2, 3, 4, 5};
size_t n = ARRAY_SIZE(numeros); // 5

// Bug: não funciona com ponteiros
void processar(int arr[]) {
    size_t n = ARRAY_SIZE(arr); // BUG: retorna sizeof(ponteiro)!
}
```

```zig
// Em Zig, slices carregam o tamanho
const numeros = [_]i32{ 1, 2, 3, 4, 5 };
const n = numeros.len; // 5

fn processar(arr: []const i32) void {
    const n = arr.len; // Sempre correto
    _ = n;
}
```

### STRINGIFY e CONCAT

```c
#define STRINGIFY(x) #x
#define CONCAT(a, b) a ## b
```

```zig
// Zig: usar comptime para geração de nomes
fn stringify(comptime valor: anytype) []const u8 {
    return @typeName(@TypeOf(valor));
}

// Para concatenação de strings em comptime:
fn nomeCompleto(comptime prefixo: []const u8, comptime sufixo: []const u8) []const u8 {
    return prefixo ++ sufixo;
}
const NOME = nomeCompleto("meu_", "campo"); // "meu_campo"
```

## Compilação Condicional

### C

```c
#ifdef DEBUG
    #define LOG(msg) printf("DEBUG: %s\n", msg)
#else
    #define LOG(msg) ((void)0)
#endif

#if defined(__linux__)
    #include <sys/epoll.h>
#elif defined(__APPLE__)
    #include <sys/event.h>
#elif defined(_WIN32)
    #include <winsock2.h>
#endif

#ifndef TIMEOUT
    #define TIMEOUT 30
#endif
```

### Zig

```zig
const builtin = @import("builtin");
const std = @import("std");

fn log(comptime msg: []const u8) void {
    if (builtin.mode == .Debug) {
        std.debug.print("DEBUG: {s}\n", .{msg});
    }
    // Em release, esta função compila para noop
}

// Plataforma
const os_api = if (builtin.os.tag == .linux)
    @import("linux_epoll.zig")
else if (builtin.os.tag == .macos)
    @import("macos_kqueue.zig")
else if (builtin.os.tag == .windows)
    @import("windows_iocp.zig")
else
    @compileError("OS não suportado");

// Valor padrão (sem #ifndef)
const TIMEOUT: u32 = if (@hasDecl(@import("config.zig"), "timeout"))
    @import("config.zig").timeout
else
    30;
```

## Header Guards

### C

```c
#ifndef MINHA_LIB_H
#define MINHA_LIB_H

typedef struct {
    int x, y;
} Ponto;

int somar(int a, int b);

#endif // MINHA_LIB_H
```

### Zig

```zig
// Não necessário em Zig!
// Cada arquivo é um módulo — não existe inclusão dupla
// minha_lib.zig

pub const Ponto = struct {
    x: i32,
    y: i32,
};

pub fn somar(a: i32, b: i32) i32 {
    return a + b;
}
```

Zig elimina completamente a necessidade de header guards. O sistema de módulos garante que cada arquivo é processado uma vez.

## Macros com Variadic Arguments

### C

```c
#define LOG_ERROR(fmt, ...) fprintf(stderr, "ERRO: " fmt "\n", ##__VA_ARGS__)
#define LOG_INFO(fmt, ...) fprintf(stdout, "INFO: " fmt "\n", ##__VA_ARGS__)

LOG_ERROR("Conexão falhou: %s", strerror(errno));
```

### Zig

```zig
fn logError(comptime fmt: []const u8, args: anytype) void {
    std.debug.print("ERRO: " ++ fmt ++ "\n", args);
}

fn logInfo(comptime fmt: []const u8, args: anytype) void {
    std.debug.print("INFO: " ++ fmt ++ "\n", args);
}

logError("Conexão falhou: {s}", .{mensagem_erro});
```

Veja [Error Logging](/receitas/zig-error-logging/) para padrões de log mais avançados.

## Type-Generic Macros (_Generic)

### C11

```c
#define imprimir(x) _Generic((x), \
    int: imprimir_int, \
    float: imprimir_float, \
    char*: imprimir_string \
)(x)
```

### Zig

```zig
fn imprimir(valor: anytype) void {
    const T = @TypeOf(valor);
    switch (@typeInfo(T)) {
        .int => std.debug.print("{}\n", .{valor}),
        .float => std.debug.print("{d:.2}\n", .{valor}),
        .pointer => |p| {
            if (p.child == u8) {
                std.debug.print("{s}\n", .{valor});
            }
        },
        else => std.debug.print("{any}\n", .{valor}),
    }
}
```

## Macros para Geração de Código (X-Macros)

### C

```c
#define ERROS \
    X(OK, "Sucesso") \
    X(NOT_FOUND, "Não encontrado") \
    X(TIMEOUT, "Timeout") \
    X(PERMISSION, "Sem permissão")

// Gerar enum
typedef enum {
    #define X(nome, desc) ERRO_##nome,
    ERROS
    #undef X
} Erro;

// Gerar função de string
const char* erro_para_string(Erro e) {
    switch (e) {
        #define X(nome, desc) case ERRO_##nome: return desc;
        ERROS
        #undef X
    }
}
```

### Zig

```zig
const ErroInfo = struct {
    nome: []const u8,
    descricao: []const u8,
};

const erros = [_]ErroInfo{
    .{ .nome = "OK", .descricao = "Sucesso" },
    .{ .nome = "NOT_FOUND", .descricao = "Não encontrado" },
    .{ .nome = "TIMEOUT", .descricao = "Timeout" },
    .{ .nome = "PERMISSION", .descricao = "Sem permissão" },
};

const Erro = enum {
    ok,
    not_found,
    timeout,
    permission,

    pub fn descricao(self: Erro) []const u8 {
        return erros[@intFromEnum(self)].descricao;
    }
};
```

## Conclusão

O `comptime` de Zig substitui todo o preprocessador C com vantagens claras: tipagem, escopo, debugging, e sem efeitos colaterais surpresa. A maioria das macros C se traduz diretamente para funções Zig com `anytype` ou `comptime`, resultando em código mais seguro e mais legível.

Para mais sobre comptime, veja [Comptime em Zig](/tutoriais/comptime-em-zig/). Para a migração completa de C para Zig, consulte [Guia de Migração: C para Zig](/tutoriais/migrar-de-c-para-zig/) e [Como Migrar um Projeto C para Zig](/artigos/migrar-projeto-c-para-zig/).
