---
title: "Interoperabilidade Zig e C: Guia Completo"
url: "https://ziglang.com.br/artigos/zig-interoperabilidade-c/"
markdown_url: "https://ziglang.com.br/artigos/zig-interoperabilidade-c.MD"
description: "Aprenda a usar bibliotecas C em Zig com @cImport, chamar Zig a partir de C e integrar projetos existentes. Exemplos práticos com SQLite, zlib e mais."
date: "2026-03-29"
author: ""
---

# Interoperabilidade Zig e C: Guia Completo

Aprenda a usar bibliotecas C em Zig com @cImport, chamar Zig a partir de C e integrar projetos existentes. Exemplos práticos com SQLite, zlib e mais.


# Interoperabilidade Zig e C: Como Usar Bibliotecas C em Zig

Uma das maiores vantagens de Zig é a **interoperabilidade nativa com C** — sem wrappers manuais, sem FFI complicado, sem overhead. O compilador Zig entende headers C diretamente, e o código gerado é ABI-compatível com C. Isso significa que todo o ecossistema de bibliotecas C, construído ao longo de décadas, está disponível para uso imediato em Zig.

Neste guia, vamos explorar como importar e usar bibliotecas C em projetos Zig, como exportar funções Zig para uso em projetos C, e veremos exemplos práticos com bibliotecas reais como SQLite e zlib.

> Se você está começando com Zig, confira nosso artigo [Por que aprender Zig](/artigos/por-que-aprender-zig/) e o [cheatsheet de interop C](/cheatsheets/c-interop/).

## Por Que a Interop com C é Importante

C é a lingua franca da programação de sistemas. Bibliotecas como OpenSSL, SQLite, zlib, POSIX e drivers de hardware são todas escritas em C. Qualquer linguagem que pretenda competir nesse espaço **precisa** interagir com código C de forma eficiente.

Diferente de linguagens como Rust (que usa `bindgen` e `unsafe` blocks) ou Go (que precisa do `cgo` com overhead de performance), Zig resolve isso no nível do compilador:

- **`@cImport`** traduz headers C automaticamente para tipos Zig
- **Zero overhead** — chamadas são diretas, sem marshalling
- **ABI compatível** — structs, enums e funções seguem o layout C
- O [build system do Zig](/artigos/zig-build-system-guia/) facilita a compilação e linking

> Para uma comparação detalhada com Rust, veja [Zig vs Rust](/artigos/zig-vs-rust/). Para Go, confira [Zig vs Go](/artigos/zig-vs-go/).

## Importando Headers C com @cImport

O `@cImport` é o coração da interoperabilidade. Ele aceita diretivas como `@cInclude`, `@cDefine` e `@cUndef`:

```zig
// Importando a biblioteca padrão C
const c = @cImport({
    @cInclude("stdio.h");
    @cInclude("stdlib.h");
});

pub fn main() void {
    // Usando printf diretamente
    _ = c.printf("Hello from Zig using C printf!\n");

    // Alocando memória com malloc
    const ptr = c.malloc(100);
    if (ptr) |p| {
        c.free(p);
    }
}
```

O compilador Zig lê o header C, traduz os tipos e funções para equivalentes Zig e disponibiliza tudo no namespace `c`. Não precisa escrever bindings manualmente — o compilador faz isso por você.

### Definindo Macros com @cDefine

Algumas bibliotecas C dependem de macros de pré-processador. Você pode defini-las antes do include:

```zig
const c = @cImport({
    // Habilitar funcionalidades POSIX
    @cDefine("_POSIX_C_SOURCE", "200809L");
    @cInclude("signal.h");
    @cInclude("unistd.h");
});
```

> Consulte o [glossário de comptime](/glossario/comptime/) para entender como Zig resolve essas importações em tempo de compilação.

## Exemplo Prático: Usando SQLite em Zig

SQLite é uma das bibliotecas C mais usadas no mundo. Veja como integrá-la:

```zig
const std = @import("std");
const c = @cImport({
    @cInclude("sqlite3.h");
});

pub fn main() !void {
    var db: ?*c.sqlite3 = null;

    // Abrir banco de dados
    const rc = c.sqlite3_open(":memory:", &db);
    if (rc != c.SQLITE_OK) {
        std.debug.print("Erro ao abrir DB: {s}\n", .{c.sqlite3_errmsg(db)});
        return error.DatabaseOpenFailed;
    }
    defer _ = c.sqlite3_close(db);

    // Criar tabela
    var err_msg: ?[*:0]u8 = null;
    const sql = "CREATE TABLE usuarios (id INTEGER PRIMARY KEY, nome TEXT);";
    const create_rc = c.sqlite3_exec(db, sql, null, null, &err_msg);
    if (create_rc != c.SQLITE_OK) {
        std.debug.print("Erro SQL: {s}\n", .{err_msg.?});
        c.sqlite3_free(err_msg);
        return error.SqlError;
    }

    // Inserir dados
    const insert_sql = "INSERT INTO usuarios (nome) VALUES ('Maria'), ('João');";
    _ = c.sqlite3_exec(db, insert_sql, null, null, null);

    std.debug.print("SQLite integrado com sucesso!\n", .{});
}
```

Para compilar, configure o [build.zig](/glossario/build-zig/) para linkar com SQLite:

```zig
// No build.zig
exe.linkSystemLibrary("sqlite3");
exe.linkLibC();
```

> Para mais sobre integrações com bancos de dados, veja [Zig e Banco de Dados](/artigos/zig-banco-dados-integracoes/).

## Exemplo Prático: Compressão com zlib

Outro caso comum — usar zlib para compressão:

```zig
const std = @import("std");
const c = @cImport({
    @cInclude("zlib.h");
});

pub fn compress_data(input: []const u8, output: []u8) !usize {
    var dest_len: c.uLongf = @intCast(output.len);
    const src_len: c.uLong = @intCast(input.len);

    const result = c.compress(
        output.ptr,
        &dest_len,
        input.ptr,
        src_len,
    );

    if (result != c.Z_OK) {
        return error.CompressionFailed;
    }

    return @intCast(dest_len);
}

pub fn main() !void {
    const data = "Zig e C trabalhando juntos! " ** 100;
    var compressed: [4096]u8 = undefined;

    const compressed_size = try compress_data(data, &compressed);
    std.debug.print("Original: {d} bytes → Comprimido: {d} bytes\n", .{
        data.len,
        compressed_size,
    });
}
```

## Exportando Funções Zig para C

A interop funciona nos dois sentidos. Use `export` para tornar funções Zig chamáveis de C:

```zig
// lib.zig — biblioteca Zig exportada para C
const std = @import("std");

// Função callable de C
export fn zig_soma(a: i32, b: i32) i32 {
    return a + b;
}

// Struct com layout C
const Ponto = extern struct {
    x: f64,
    y: f64,
};

export fn zig_distancia(p1: Ponto, p2: Ponto) f64 {
    const dx = p1.x - p2.x;
    const dy = p1.y - p2.y;
    return @sqrt(dx * dx + dy * dy);
}

// Callback compatível com C
export fn zig_callback(data: ?*anyopaque) void {
    _ = data;
    std.debug.print("Callback Zig chamado de C!\n", .{});
}
```

Do lado C:

```c
// main.c — usando a lib Zig
#include <stdio.h>

// Declarações das funções Zig
extern int zig_soma(int a, int b);

typedef struct {
    double x;
    double y;
} Ponto;

extern double zig_distancia(Ponto p1, Ponto p2);
extern void zig_callback(void *data);

int main() {
    printf("Soma: %d\n", zig_soma(10, 20));

    Ponto p1 = {0.0, 0.0};
    Ponto p2 = {3.0, 4.0};
    printf("Distância: %.2f\n", zig_distancia(p1, p2));

    zig_callback(NULL);
    return 0;
}
```

Esse padrão é ideal para migrar projetos C para Zig de forma incremental. Se está considerando essa migração, confira nosso guia [Migrar Projeto C para Zig](/artigos/migrar-projeto-c-para-zig/).

## Tipos e Compatibilidade ABI

Para que a interop funcione corretamente, os tipos precisam ser ABI-compatíveis:

| Tipo C | Tipo Zig | Notas |
|--------|----------|-------|
| `int` | `c_int` | Tamanho depende da plataforma |
| `unsigned long` | `c_ulong` | Usado em muitas APIs POSIX |
| `char *` | `[*:0]u8` | String terminada em null |
| `void *` | `?*anyopaque` | Ponteiro genérico opaco |
| `struct` | `extern struct` | Layout C garantido |
| `enum` | `extern enum` | Valores numéricos compatíveis |
| `size_t` | `usize` | Tamanho de ponteiro |

Use sempre `extern struct` ao invés de `struct` quando a struct será compartilhada com código C — isso garante que Zig use o mesmo layout de memória que o compilador C usaria.

> Para mais sobre ponteiros e tipos em Zig, consulte o [glossário de pointer types](/glossario/pointer-types/) e [slice](/glossario/slice/).

## translate-c: Convertendo Código C para Zig

O comando `zig translate-c` converte código C para Zig automaticamente. É útil para entender como Zig interpreta headers ou migrar código:

```bash
# Traduzir um header
zig translate-c /usr/include/stdio.h > stdio_zig.zig

# Com flags de pré-processador
zig translate-c -I/usr/local/include mylib.h
```

O código gerado não é idiomático, mas funciona como ponto de partida para refatoração. Use junto com o [comptime](/artigos/comptime-zig-metaprogramacao/) para criar wrappers mais elegantes.

## Configurando o Build System

O [build system do Zig](/artigos/zig-build-system-guia/) simplifica o linking com bibliotecas C:

```zig
// build.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 = "meu-projeto",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });

    // Linkar com bibliotecas C do sistema
    exe.linkSystemLibrary("sqlite3");
    exe.linkSystemLibrary("z"); // zlib
    exe.linkLibC();

    // Adicionar caminhos de include personalizados
    exe.addIncludePath(b.path("vendor/include"));
    exe.addLibraryPath(b.path("vendor/lib"));

    b.installArtifact(exe);
}
```

Para projetos com [cross-compilation](/artigos/zig-cross-compilation-guia/), o Zig resolve automaticamente os sysroots e headers para o target desejado — uma vantagem enorme sobre toolchains tradicionais.

> Veja mais detalhes em [build.zig no glossário](/glossario/build-zig/) e o [overview do build system](/ecossistema/zig-build-system-overview/).

## Boas Práticas

1. **Use `extern struct`** para qualquer struct compartilhada com C
2. **Sempre chame `linkLibC()`** quando usar `@cImport`
3. **Prefira wrappers idiomáticos** — wraps funções C em APIs Zig com [error handling](/artigos/zig-error-handling-boas-praticas/) adequado
4. **Teste a interop** — use o [framework de testes do Zig](/artigos/zig-testes-guia-completo/) para validar chamadas C
5. **Documente conversões de tipo** — especialmente ponteiros opcionais vs nullable
6. **Verifique [alignment](/glossario/alignment/)** ao passar structs entre Zig e C

## Comparação com Outras Linguagens

A interop com C é um diferencial de Zig frente a outras linguagens de sistemas:

- **Rust** usa `bindgen` + `unsafe` blocks, com overhead cognitivo significativo. Veja a [comparação completa Zig vs Rust](/artigos/zig-vs-rust/) e explore o <a href="https://rustlang.com.br/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'rustlang.com.br' })">ecossistema Rust em rustlang.com.br</a>
- **Go** usa `cgo` que adiciona overhead de performance nas chamadas. Compare em detalhes em [Zig vs Go](/artigos/zig-vs-go/) e saiba mais sobre <a href="https://golang.com.br/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'golang.com.br' })">Go em golang.com.br</a>
- **Zig** — chamadas diretas, zero overhead, tradução automática de headers

Para desenvolvedores vindo de outras linguagens, temos guias específicos: [Zig para programadores Kotlin](/artigos/zig-para-programadores-kotlin/) (veja também <a href="https://kotlin.dev.br/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'kotlin.dev.br' })">kotlin.dev.br</a>), [Java](/artigos/zig-para-programadores-java/) e [C#](/artigos/zig-para-programadores-csharp/).

## Conclusão

A interoperabilidade com C é um dos pontos mais fortes de Zig. O `@cImport` elimina a necessidade de bindings manuais, o `export` permite migração incremental, e o build system simplifica o linking. Com o vasto ecossistema de bibliotecas C à disposição, você pode começar a escrever código Zig hoje sem abrir mão de decades de software existente.

Para continuar aprendendo, explore o [cheatsheet de interop C](/cheatsheets/c-interop/), veja como funciona o [build system do Zig](/artigos/zig-build-system-guia/) e confira o [roadmap de desenvolvedor Zig](/carreira/roadmap-desenvolvedor-zig/).
