---
title: "Chamar Funções C de Zig"
url: "https://ziglang.com.br/receitas/chamar-fun%C3%A7%C3%B5es-c-de-zig/"
markdown_url: "https://ziglang.com.br/receitas/chamar-fun%C3%A7%C3%B5es-c-de-zig.MD"
description: "Receita prática para chamar funções C de Zig. Uso de @cImport, @cInclude, linking de bibliotecas, passagem de tipos e conversão de dados entre C e Zig."
date: "2026-02-21"
author: "Zig Brasil"
---

# Chamar Funções C de Zig

Receita prática para chamar funções C de Zig. Uso de @cImport, @cInclude, linking de bibliotecas, passagem de tipos e conversão de dados entre C e Zig.


## Introdução

A interoperabilidade com C é uma das features mais poderosas de Zig. Com `@cImport` e `@cInclude`, você pode importar headers C diretamente e chamar funções C sem escrever bindings manuais. Esta receita cobre os padrões mais comuns.

Para o tutorial completo, veja [Interoperabilidade C-Zig](/tutoriais/zig-c-interoperabilidade/). Para conversão de ponteiros, consulte [Converter Ponteiros C para Zig](/tutoriais/zig-converter-ponteiros-c/). Para portar bibliotecas inteiras, veja [Portar uma Biblioteca C para Zig](/tutoriais/zig-portar-biblioteca-c/).

## Pré-requisitos

- Zig instalado (versão 0.13+). Veja o [guia de instalação](/tutoriais/como-instalar-zig/)
- Conhecimento básico de Zig e C. Consulte a [introdução ao Zig](/tutoriais/introducao-ao-zig/)

## Importar Header C

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

pub fn main() void {
    _ = c.printf("Olá do C! %d\n", @as(c_int, 42));
}
```

## Chamar Funções da libc

### Funções de String

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

fn comprimentoC(str: [*:0]const u8) usize {
    return c.strlen(str);
}

pub fn main() void {
    const texto: [*:0]const u8 = "Zig Brasil";
    const len = comprimentoC(texto);
    std.debug.print("Comprimento: {}\n", .{len});
}
```

### Funções Matemáticas

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

fn hipotenusa(a: f64, b: f64) f64 {
    return c.hypot(a, b);
}

test "hipotenusa" {
    const resultado = hipotenusa(3.0, 4.0);
    try std.testing.expectApproxEqAbs(@as(f64, 5.0), resultado, 0.001);
}
```

## Usar Biblioteca do Sistema

### SQLite

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

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

    const rc = c.sqlite3_open(":memory:", &db);
    if (rc != c.SQLITE_OK) {
        std.debug.print("Erro: {s}\n", .{c.sqlite3_errmsg(db)});
        return error.SqliteError;
    }
    defer _ = c.sqlite3_close(db);

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

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

No build.zig:

```zig
exe.linkSystemLibrary("sqlite3");
exe.linkLibC();
```

### zlib

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

fn obterVersaoZlib() []const u8 {
    const versao = c.zlibVersion();
    return std.mem.span(versao);
}

test "versão do zlib" {
    const versao = obterVersaoZlib();
    try std.testing.expect(versao.len > 0);
}
```

Veja [Compressão com zlib](/receitas/zig-comprimir-zlib/) para exemplos completos.

## Converter Tipos entre C e Zig

### Strings

```zig
// Zig string para C string
fn zigParaC(allocator: std.mem.Allocator, zig_str: []const u8) ![*:0]u8 {
    return allocator.dupeZ(u8, zig_str);
}

// C string para Zig string (slice)
fn cParaZig(c_str: [*:0]const u8) []const u8 {
    return std.mem.span(c_str);
}

test "conversão de strings" {
    const allocator = std.testing.allocator;

    const c_str = try zigParaC(allocator, "Zig Brasil");
    defer allocator.free(c_str[0 .. std.mem.len(c_str) + 1]);

    const volta = cParaZig(c_str);
    try std.testing.expectEqualStrings("Zig Brasil", volta);
}
```

### Arrays e Buffers

```zig
fn processarComC(dados: []u8) void {
    // Passar slice Zig para função C que espera (ptr, len)
    c.processar(dados.ptr, dados.len);
}

fn receberDeC() ![]u8 {
    var buffer: [1024]u8 = undefined;
    const n = c.ler_dados(&buffer, buffer.len);
    return buffer[0..@intCast(n)];
}
```

## Callbacks

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

fn meuCallback(dados: ?*anyopaque) callconv(.C) void {
    if (dados) |ptr| {
        const contexto: *Contexto = @ptrCast(@alignCast(ptr));
        contexto.processar();
    }
}

pub fn registrar(contexto: *Contexto) void {
    c.registrar_callback(meuCallback, @ptrCast(contexto));
}
```

## Structs C

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

// Structs C são importadas automaticamente
fn criarPonto() c.Ponto {
    return c.Ponto{
        .x = 1.0,
        .y = 2.0,
    };
}

// Acessar campos
fn distancia(p: c.Ponto) f64 {
    return @sqrt(p.x * p.x + p.y * p.y);
}
```

## Configuração do build.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 = "meu-programa",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });

    // Incluir diretório de headers
    exe.addIncludePath(b.path("c-headers"));

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

    // Ou compilar código C junto
    exe.addCSourceFile(.{
        .file = b.path("c-src/minha_lib.c"),
        .flags = &.{ "-std=c11", "-Wall" },
    });

    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/).

## Erros Comuns

### 1. Esquecer de linkar libc

```zig
// Se usar @cImport, geralmente precisa:
exe.linkLibC();
```

### 2. Casting de ponteiros incorreto

```zig
// ERRADO: direto
const ptr: *MeuTipo = c_ptr;

// CORRETO: com cast e alinhamento
const ptr: *MeuTipo = @ptrCast(@alignCast(c_ptr));
```

### 3. Strings sem null terminator

```zig
// Zig strings NÃO são null-terminated por padrão
const str: []const u8 = "Zig";
// NÃO passe str.ptr diretamente para funções C que esperam \0

// Use dupeZ para adicionar null terminator
const c_str = try allocator.dupeZ(u8, str);
defer allocator.free(c_str[0..str.len + 1]);
```

## Conclusão

Chamar código C de Zig é direto e seguro. `@cImport` importa headers automaticamente, e o sistema de tipos de Zig garante conversões corretas entre os mundos C e Zig. Para projetos maiores, considere criar wrappers idiomáticos como descrito em [Portar uma Biblioteca C para Zig](/tutoriais/zig-portar-biblioteca-c/).

Para mais sobre interop, veja [Interoperabilidade C-Zig](/tutoriais/zig-c-interoperabilidade/), [Converter Ponteiros C para Zig](/tutoriais/zig-converter-ponteiros-c/) e [Substituir Macros C por Comptime](/tutoriais/zig-substituir-macros-c/).
