---
title: "Perguntas de Entrevista sobre Interoperabilidade C em Zig"
url: "https://ziglang.com.br/entrevistas/perguntas-de-entrevista-sobre-interoperabilidade-c-em-zig/"
markdown_url: "https://ziglang.com.br/entrevistas/perguntas-de-entrevista-sobre-interoperabilidade-c-em-zig.MD"
description: "Perguntas de entrevista sobre interoperabilidade entre Zig e C: importar headers, FFI, ABI, linkagem, tradução de tipos e migração de codebases."
date: "2026-02-21"
author: "Zig Brasil"
---

# Perguntas de Entrevista sobre Interoperabilidade C em Zig

Perguntas de entrevista sobre interoperabilidade entre Zig e C: importar headers, FFI, ABI, linkagem, tradução de tipos e migração de codebases.


# Perguntas de Entrevista sobre Interoperabilidade C em Zig

A interoperabilidade com C é um dos pilares de Zig. A capacidade de importar headers C, chamar funções C sem overhead e linkar com bibliotecas C existentes torna Zig uma escolha prática para migração gradual de codebases C e integração com o vasto ecossistema de bibliotecas C existentes. Entrevistadores testam esse conhecimento especialmente quando a empresa possui código legado em C.

## Fundamentos

### Como importar e usar uma biblioteca C em Zig?

Zig pode importar headers C diretamente com `@cImport`:

```zig
const c = @cImport({
    @cInclude("stdio.h");
    @cInclude("stdlib.h");
});

pub fn main() void {
    _ = c.printf("Hello from C!\n");
    const ptr = c.malloc(100);
    if (ptr) |p| {
        c.free(p);
    }
}
```

O compilador Zig traduz os tipos C para tipos Zig automaticamente.

### Qual a diferença entre `@cImport` e usar o Zig build system para C?

`@cImport` traduz headers em tempo de compilação. O build system permite compilar arquivos `.c` junto com Zig, linkar bibliotecas estáticas/dinâmicas e gerenciar flags de compilação. Em projetos reais, ambos são usados juntos — veja [build system](/entrevistas/perguntas-build-system-zig/).

### Como os tipos C são mapeados para Zig?

| Tipo C | Tipo Zig |
|--------|----------|
| `int` | `c_int` |
| `char*` | `[*c]u8` |
| `void*` | `?*anyopaque` |
| `size_t` | `usize` |
| `NULL` | `null` |
| `struct X` | Struct Zig equivalente |

Ponteiros C (`[*c]T`) permitem aritmética de ponteiros e podem ser nulos, diferente de ponteiros Zig regulares.

### Como chamar Zig a partir de C?

Exporte funções Zig com `export`:

```zig
export fn somar(a: c_int, b: c_int) c_int {
    return a + b;
}
```

A função fica disponível para linkagem com código C usando o nome `somar`.

## Perguntas Avançadas

### Quais são os desafios comuns de interop C/Zig?

- **Gerenciamento de memória misto:** Código C usa malloc/free, código Zig usa allocators. É essencial manter consistência sobre quem aloca e quem libera.
- **Strings:** Strings C são null-terminated (`[*:0]const u8`), slices Zig não são. Use `std.mem.span` para converter.
- **Error handling:** C usa códigos de retorno, Zig usa error unions. Wrappers devem traduzir entre os dois.
- **Callbacks:** Function pointers C podem não ser compatíveis diretamente com closures Zig (que capturam contexto).

### Descreva uma estratégia de migração gradual de C para Zig.

1. Comece linkando o código C existente com o build system Zig
2. Escreva testes para módulos C existentes usando `std.testing` de Zig
3. Migre módulos isolados um por um, começando pelos menores
4. Use `@cImport` para que o novo código Zig chame o C restante
5. Exporte funções Zig para que o código C possa chamar Zig
6. Gradualmente substitua até o código inteiro ser Zig

Essa abordagem é usada por empresas como [Uber](/cases/case-uber-zig/) e [Cloudflare](/cases/case-cloudflare-zig/). Veja também [transição de C para Zig](/carreira/transicao-c-para-zig/).

### Como escrever um wrapper Zig idiomático para uma biblioteca C?

O padrão recomendado é criar um módulo Zig que encapsula a API C, traduzindo tipos e erros para idiomas Zig:

```zig
const c = @cImport(@cInclude("sqlite3.h"));

pub const Database = struct {
    db: *c.sqlite3,

    pub fn open(path: [:0]const u8) !Database {
        var db: ?*c.sqlite3 = null;
        const rc = c.sqlite3_open(path.ptr, &db);
        if (rc != c.SQLITE_OK) return error.DatabaseOpenFailed;
        return .{ .db = db.? };
    }

    pub fn close(self: *Database) void {
        _ = c.sqlite3_close(self.db);
    }

    pub fn exec(self: *Database, sql: [:0]const u8) !void {
        var errmsg: [*c]u8 = null;
        const rc = c.sqlite3_exec(self.db, sql.ptr, null, null, &errmsg);
        if (rc != c.SQLITE_OK) {
            if (errmsg) |msg| c.sqlite3_free(msg);
            return error.QueryFailed;
        }
    }
};
```

Observe os padrões: strings C usam `[:0]const u8` (null-terminated), erros C são traduzidos para error unions Zig, e o gerenciamento de memória fica explícito. O chamador usa a API como se fosse uma biblioteca Zig nativa, sem precisar conhecer os detalhes de C.

### Como usar `translate-c` para migração automática de código C?

O comando `zig translate-c` converte arquivos C para Zig automaticamente:

```bash
zig translate-c arquivo.c > arquivo_traduzido.zig
```

O resultado é um bom ponto de partida para migração, mas requer ajustes manuais: ponteiros `[*c]T` precisam ser convertidos para slices ou ponteiros Zig mais apropriados, macros C que `@cImport` não consegue traduzir precisam de equivalentes Zig, e o estilo de error handling precisa ser adaptado. Use `translate-c` como ferramenta de apoio, não como solução definitiva.

### Quais cuidados tomar com callbacks C em Zig?

Callbacks em C são function pointers simples sem captura de contexto. Em Zig, closures capturam contexto, o que as torna incompatíveis com callbacks C diretamente. A solução é o padrão "userdata pointer":

```zig
// A biblioteca C espera: void callback(void* userdata, int evento)
const MeuContexto = struct { contador: u32, limite: u32 };

fn meuCallback(userdata: ?*anyopaque, evento: c_int) callconv(.C) void {
    const ctx: *MeuContexto = @ptrCast(@alignCast(userdata));
    ctx.contador += 1;
    if (ctx.contador >= ctx.limite) {
        // lógica dependente de contexto
    }
}

// Registro do callback com userdata
var contexto = MeuContexto{ .contador = 0, .limite = 10 };
c.registrar_callback(meuCallback, &contexto);
```

O `callconv(.C)` é obrigatório para garantir que a função use a convenção de chamada C (cdecl) e seja compatível com ponteiros de função C. Esse padrão é a forma idiomática de lidar com callbacks em bibliotecas C a partir de Zig.

Complemente com [perguntas de build system](/entrevistas/perguntas-build-system-zig/) e explore o [ecossistema](/ecossistema/) de bibliotecas. Pratique com [tutoriais](/tutoriais/) e [projetos](/projetos/) que integram C e Zig.
