---
title: "Zig vs C Moderno (C23): Segurança, Build, Performance e Migração"
url: "https://ziglang.com.br/artigos/zig-vs-c-moderno/"
markdown_url: "https://ziglang.com.br/artigos/zig-vs-c-moderno.MD"
description: "Zig vs C moderno (C23): comparação prática de segurança de memória, undefined behavior, build.zig, cross-compilation, performance, interop C e migração gradual."
date: "2026-02-21"
author: "Zig Brasil"
---

# Zig vs C Moderno (C23): Segurança, Build, Performance e Migração

Zig vs C moderno (C23): comparação prática de segurança de memória, undefined behavior, build.zig, cross-compilation, performance, interop C e migração gradual.


## Introdução

C23 é a versão mais recente do padrão ISO C e trouxe melhorias importantes: `constexpr`, `typeof`, `nullptr`, `_BitInt`, atributos padronizados, `#embed` e uma semântica mais clara para funções sem parâmetros. A pergunta prática para quem escreve sistemas é outra: **C23 resolve os problemas que fazem equipes considerarem Zig?**

A resposta curta é: C23 moderniza a sintaxe e reduz algumas dores, mas não muda a natureza da linguagem. C continua sendo excelente quando ABI, portabilidade histórica e ecossistema legado são mais importantes que ergonomia. Zig tenta ocupar o mesmo espaço operacional de C com outra proposta: build integrado, cross-compilation simples, `comptime`, error unions, slices com tamanho, allocators explícitos e verificações úteis em debug.

Este artigo compara Zig com C23 especificamente — não com o C de 1989, mas com o C mais moderno disponível. Para comparação com C++, veja [Zig vs C++](/artigos/zig-vs-cpp/). Para migração prática, 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/).

## Resposta Rápida: Zig ou C23?

| Cenário | Escolha mais provável | Motivo |
|---|---|---|
| Código legado com ABI C pública e toolchain já aprovado | C23 | Menor risco organizacional e compatibilidade máxima |
| Projeto novo de CLI, runtime, ferramenta interna ou biblioteca de sistemas | Zig | Build/cross-compilation integrados e menos cola de infraestrutura |
| Firmware/regulatório com MISRA/CERT C obrigatório | C23 | O ecossistema de certificação ainda gira em torno de C |
| Migração gradual de uma base C existente | Zig + C | `@cImport`, `zig cc` e wrappers permitem trocar partes aos poucos |
| Ensino de programação de sistemas com feedback rápido | Zig | Erros explícitos, testes integrados e debug checks ajudam a aprender |
| Biblioteca que precisa ser consumida por qualquer linguagem via ABI | C23 ou Zig expondo ABI C | A ABI C continua sendo o contrato universal |

A regra prática é simples: **C23 é a melhor evolução conservadora de C; Zig é a melhor aposta quando você quer manter controle de baixo nível, mas remover parte do atrito histórico de C**.

## O Que C23 Trouxe de Novo

C23 é uma evolução significativa:

- **`constexpr`**: Variáveis e funções avaliadas em compilação
- **`typeof`**: Inferência de tipo (finalmente!)
- **`nullptr`**: Constante nula tipada (substitui `NULL`)
- **`_BitInt(N)`**: Inteiros de largura arbitrária
- **Atributos padrão**: `[[nodiscard]]`, `[[maybe_unused]]`, `[[deprecated]]`
- **`auto`**: Inferência de tipo para variáveis locais
- **`#embed`**: Incluir dados binários diretamente
- **Funções sem parâmetros**: `void f()` agora significa zero parâmetros

Essas melhorias são bem-vindas, mas Zig foi projetado desde o início para resolver problemas que C23 apenas mitiga.

## Segurança de Memória

### C23

C23 **não resolve** os problemas fundamentais de segurança de C:

```c
// Todos estes bugs AINDA existem em C23:
int* p = malloc(sizeof(int));
free(p);
*p = 42; // use-after-free: undefined behavior

int arr[10];
arr[15] = 0; // buffer overflow: undefined behavior

char* s = NULL;
printf("%s", s); // null dereference: undefined behavior
```

C23 adicionou `nullptr` e `constexpr`, mas a linguagem continua fundamentalmente insegura em relação a memória.

### Zig

Zig resolve esses problemas com verificações de segurança em tempo de compilação e runtime:

```zig
// Use-after-free: detectado em debug
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = gpa.allocator();
const p = try allocator.create(i32);
allocator.destroy(p);
// p.* = 42; // Erro: uso de memória liberada (em debug)

// Buffer overflow: sempre verificado
var arr: [10]i32 = undefined;
// arr[15] = 0; // panic: index out of bounds

// Null dereference: prevenido pelo sistema de tipos
const s: ?[]const u8 = null;
// s.len; // Erro de compilação: precisa unwrap optional
if (s) |valor| {
    std.debug.print("{s}\n", .{valor});
}
```

Veja [Segurança de Memória em Zig](/tutoriais/zig-seguranca-memoria/) e [Detectar Vazamentos](/receitas/zig-detectar-memory-leak/).

## Metaprogramação: constexpr vs Comptime

### C23 constexpr

C23 `constexpr` é limitado — não permite loops, chamadas de função arbitrárias ou alocação em tempo de compilação:

```c
// C23: constexpr básico
constexpr int MAX_TAMANHO = 1024;
constexpr int quadrado(int x) { return x * x; }
constexpr int tabela[5] = {0, 1, 4, 9, 16};
```

### Zig comptime

Zig `comptime` executa código Zig arbitrário em tempo de compilação — incluindo loops, chamadas de função, e até criação de tipos:

```zig
// Zig: comptime completo
fn criarLookupTable(comptime n: usize) [n]u32 {
    var tabela: [n]u32 = undefined;
    for (&tabela, 0..) |*entry, i| {
        entry.* = @intCast(i * i);
    }
    return tabela;
}

const TABELA = criarLookupTable(256); // calculada em compilação

fn HashMap(comptime K: type, comptime V: type) type {
    return struct {
        // tipo inteiro criado em compilação
        entries: []Entry,
        const Entry = struct { key: K, value: V };
    };
}
```

A diferença é enorme: `constexpr` de C23 avalia expressões simples; `comptime` de Zig é uma linguagem de metaprogramação completa usando a mesma sintaxe.

## Tratamento de Erros

### C23

C23 não tem mecanismo de tratamento de erros integrado. O padrão continua sendo códigos de retorno e `errno`:

```c
FILE* f = fopen("config.txt", "r");
if (f == NULL) {
    perror("Erro ao abrir arquivo");
    return -1;
}
// fácil esquecer de verificar
```

### Zig

Zig tem error unions integrados ao sistema de tipos:

```zig
fn lerConfig(caminho: []const u8) !Config {
    const arquivo = try std.fs.cwd().openFile(caminho, .{});
    defer arquivo.close();
    // ...
}

// O compilador OBRIGA tratamento do erro
const config = lerConfig("config.txt") catch |err| {
    std.debug.print("Erro: {}\n", .{err});
    return;
};
```

Veja [Error Sets Customizados](/receitas/zig-error-set-customizado/) e [Padrões Errdefer](/receitas/zig-errdefer-pattern/).

## Sistema de Build

### C23

C23 não define um sistema de build. Desenvolvedores C usam Make, CMake, Meson, Autotools, ou outros — cada um com sua própria sintaxe e complexidade:

```makefile
CC=gcc
CFLAGS=-std=c23 -Wall -O2
programa: main.o utils.o
    $(CC) $(CFLAGS) -o $@ $^
```

### Zig

Zig tem um sistema de build integrado escrito em Zig:

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

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});
    const exe = b.addExecutable(.{
        .name = "programa",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });
    b.installArtifact(exe);
}
```

Veja [Migrar de Makefile para build.zig](/tutoriais/migrar-makefile-para-build-zig/) e [Migrar de CMake para build.zig](/tutoriais/migrar-cmake-para-build-zig/).

## Comparação Direta de Features

| Feature | C23 | Zig |
|---------|-----|-----|
| Inferência de tipo | `auto`/`typeof` (limitado) | Completa |
| Null safety | `nullptr` (sintática) | Optionals `?T` (semântica) |
| Bounds checking | Nenhum | Debug mode automático |
| Error handling | errno/códigos de retorno | Error unions integrados |
| Metaprogramação | `constexpr` (limitado) + macros | `comptime` (completo) |
| Generics | `_Generic` (muito limitado) | `comptime` generics |
| Sistema de build | Externo (Make/CMake) | Integrado (build.zig) |
| Testes | Externo (Unity, cmocka) | Integrados (`test`) |
| Cross-compilation | Via toolchain externo | Integrada |
| Package manager | Nenhum oficial | Integrado (zon) |
| Strings | `char*` (null-terminated) | Slices com tamanho |
| defer | Não existe | Sim |
| Undefined behavior | Extensivo (200+ formas) | Minimizado, detectado |

## Preprocessador vs Comptime

O preprocessador C é uma das maiores fontes de problemas. C23 não o substitui:

### C23 (preprocessador)

```c
// Problemas clássicos do preprocessador
#define MAX(a, b) ((a) > (b) ? (a) : (b))
int x = MAX(i++, j++); // bug: i++ ou j++ avaliado duas vezes

#define TAMANHO_BUFFER 1024
// Não é uma constante real, é substituição textual
```

### Zig (comptime)

```zig
fn max(a: anytype, b: @TypeOf(a)) @TypeOf(a) {
    return if (a > b) a else b;
}
// Sem efeitos colaterais duplicados — é uma função real

const TAMANHO_BUFFER: usize = 1024;
// Constante real com tipo
```

Veja [Substituir Macros C por Comptime Zig](/tutoriais/zig-substituir-macros-c/) para um guia completo.

## Interoperabilidade C-Zig

Zig pode usar código C23 diretamente:

```zig
const c = @cImport({
    @cDefine("_GNU_SOURCE", {});
    @cInclude("minha_lib_c23.h");
});

pub fn main() !void {
    const resultado = c.minha_funcao_c23();
    std.debug.print("Resultado: {}\n", .{resultado});
}
```

Veja [Interoperabilidade C-Zig](/tutoriais/zig-c-interoperabilidade/) e [Converter Ponteiros C para Zig](/tutoriais/zig-converter-ponteiros-c/).


## Performance: O Ponto Onde a Comparação Fica Menos Ideológica

Em código nativo bem escrito, Zig e C23 podem chegar a performances muito próximas. Ambos compilam para binários nativos, permitem controle de layout de dados, evitam garbage collector obrigatório e conseguem usar instruções específicas de arquitetura quando necessário. A diferença não é "Zig é sempre mais rápido" ou "C é sempre mais rápido". A diferença real está no caminho até um binário rápido, reproduzível e fácil de medir.

Em C, performance costuma depender de uma combinação externa: compilador, flags, sistema de build, bibliotecas, sanitizers, profiler e scripts de release. Em Zig, mais dessa configuração fica dentro do próprio projeto:

- `zig build -Doptimize=ReleaseFast` documenta o modo de otimização no fluxo oficial do projeto.
- `ReleaseSafe` permite uma opção intermediária quando segurança em runtime ainda importa.
- `zig cc` pode compilar dependências C com uma toolchain mais previsível.
- Cross-compilation é uma função do compilador, não uma coleção de pacotes externos por plataforma.
- Benchmarks e testes podem viver no mesmo fluxo de `zig build test`.

Para aprender a medir sem cair em microbenchmark enganoso, veja [Benchmarking em Zig: medir performance](/artigos/zig-benchmarking-medir-performance/) e, para comparação com outras linguagens de sistemas, [Zig vs Rust](/artigos/zig-vs-rust/) e [Zig vs Go](/artigos/zig-vs-go/).

## Migração Gradual: O Caso Mais Realista

Poucas equipes jogam fora uma base C grande para reescrever tudo em uma linguagem nova. O caminho mais seguro costuma ser incremental:

1. **Usar `zig cc` como compilador C** em um projeto existente para simplificar cross-compilation e releases.
2. **Criar testes de borda** para partes críticas antes de trocar implementação.
3. **Escrever novos módulos em Zig** que exponham uma ABI C simples.
4. **Importar headers C com `@cImport`** enquanto a fronteira entre as linguagens ainda muda.
5. **Mover lógica de build para `build.zig`** quando o projeto já tiver uma fatia Zig relevante.
6. **Substituir macros perigosas por funções ou `comptime`** onde houver bugs recorrentes.

Esse caminho reduz risco porque C e Zig podem conviver no mesmo binário. Você não precisa vender uma reescrita total para ganhar benefícios práticos: pode começar por uma ferramenta CLI, uma biblioteca de parsing, uma rotina de serialização, um worker de alta performance ou uma parte difícil de cross-compilar.

Leia também [Interop C em Zig](/artigos/zig-interoperabilidade-c/), [Migrar projeto C para Zig](/artigos/migrar-projeto-c-para-zig/) e [Cross-compilation em Zig](/artigos/zig-cross-compilation-guia/).

## Quando C23 Ainda Faz Sentido

- Projetos com requisitos de conformidade MISRA/CERT C
- Ecossistemas que mandatam C (Linux kernel, firmware regulatório)
- Equipes com décadas de experiência em C e resistência a mudança
- Bibliotecas que precisam de compatibilidade ABI C máxima
- Bases legadas onde a maior parte do risco está em processo, certificação e tooling, não em sintaxe

## Quando Zig É a Melhor Aposta

Zig faz mais sentido quando a equipe quer continuar perto do metal, mas está cansada de manter uma pilha de ferramentas ao redor de C. Alguns sinais fortes:

- Você precisa gerar binários para Linux, macOS, Windows, ARM e x86 sem manter múltiplas toolchains.
- O projeto tem muitos `Makefile`, scripts de release e flags duplicadas.
- O time quer remover macros perigosas sem adotar C++ ou Rust.
- Você quer testes e build reproduzíveis como parte da experiência padrão.
- Você está escrevendo uma CLI, um runtime, uma lib nativa, um parser, um servidor leve ou uma ferramenta de infraestrutura.
- Você precisa interoperar com C, mas quer escrever as novas partes com um sistema de tipos mais explícito.

## FAQ: Zig vs C Moderno

### Zig substitui C23?

Não universalmente. Zig pode substituir C em muitos projetos novos e em partes isoladas de bases existentes, mas C23 continua mais conservador para firmware regulado, bibliotecas com contrato ABI histórico e ambientes onde o compilador C é obrigatório.

### C23 ficou seguro como Zig?

Não. C23 melhora a linguagem, mas não adiciona null safety semântica, bounds checking padrão, error unions, slices com tamanho ou um modelo de allocators como parte central da experiência. Bugs clássicos de C continuam possíveis.

### Zig é mais rápido que C?

Não há resposta universal. Zig e C podem gerar código nativo extremamente rápido. A vantagem de Zig costuma aparecer mais em ergonomia de build, cross-compilation, testes e controle explícito do projeto do que em uma promessa absoluta de benchmark.

### Posso usar C e Zig no mesmo projeto?

Sim. Esse é um dos pontos fortes de Zig. Você pode importar headers C com `@cImport`, compilar C com `zig cc`, chamar bibliotecas C existentes e expor uma ABI C para consumidores externos.

### Devo aprender C antes de Zig?

Ajuda, mas não é obrigatório. C ensina a história e a ABI que ainda governam sistemas. Zig pode ser uma porta de entrada mais segura para aprender memória, ponteiros, layout e build moderno sem aceitar todas as armadilhas de C como padrão.

## Conclusão

C23 é uma melhoria real sobre C17, mas não resolve os problemas fundamentais de C: segurança de memória, undefined behavior, ausência de sistema de build, e preprocessador frágil. Zig foi projetado para resolver exatamente esses problemas mantendo o mesmo nível de controle que C oferece.

Se você está começando um projeto novo de sistemas, Zig oferece muitas das vantagens de C com segurança e ergonomia modernas. Se está mantendo código C existente, considere a migração gradual descrita em [Como Migrar um Projeto C para Zig](/artigos/migrar-projeto-c-para-zig/).

Se você está avaliando alternativas modernas ao C, confira também nosso conteúdo sobre <a href="https://rustlang.com.br/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'rustlang.com.br' })">Rust</a>, outra linguagem que busca substituir C com foco em segurança de memória.

Para começar, visite [Introdução ao Zig](/tutoriais/introducao-ao-zig/) e [Zig para Programadores C](/tutoriais/zig-para-programadores-c/).
