Cheatsheet: Interop com C em Zig
Uma das grandes forças de Zig é a integração nativa e sem fricção com código C. O compilador Zig inclui um compilador C (baseado em Clang), pode importar headers C diretamente, linkar com bibliotecas C e até compilar código C como parte do projeto — tudo sem ferramentas externas.
Importando Headers C
@cImport — Importar headers C
const std = @import("std");
const c = @cImport({
@cInclude("stdio.h");
@cInclude("stdlib.h");
@cInclude("string.h");
});
pub fn main() void {
// Chamar printf do C
_ = c.printf("Olá do C! %d\n", @as(c_int, 42));
// malloc/free do C
const ptr = c.malloc(100);
if (ptr) |p| {
defer c.free(p);
// usar o ponteiro...
}
}
Importar biblioteca de terceiros
const c = @cImport({
@cDefine("_GNU_SOURCE", {}); // #define
@cDefine("SDL_MAIN_HANDLED", {});
@cInclude("SDL2/SDL.h");
});
pub fn main() !void {
if (c.SDL_Init(c.SDL_INIT_VIDEO) != 0) {
std.debug.print("Erro SDL: {s}\n", .{c.SDL_GetError()});
return error.SDLInitFailed;
}
defer c.SDL_Quit();
// Criar janela, etc.
}
Tradução de Tipos C → Zig
Tabela de equivalência
| Tipo C | Tipo Zig | Notas |
|---|---|---|
char | u8 | Em Zig, sempre unsigned |
signed char | i8 | |
unsigned char | u8 | |
short | c_short | Geralmente i16 |
int | c_int | Geralmente i32 |
long | c_long | i32 ou i64 conforme plataforma |
long long | c_longlong | Geralmente i64 |
unsigned int | c_uint | |
size_t | usize | |
float | f32 | |
double | f64 | |
void* | ?*anyopaque | Ponteiro opaco nullable |
const char* | [*:0]const u8 | String C terminada em null |
int* | *c_int ou [*]c_int | Depende do uso |
NULL | null | |
bool (_Bool) | bool | |
struct X | traduzido automaticamente | |
enum X | traduzido automaticamente |
Conversões de ponteiros
const c = @cImport(@cInclude("string.h"));
pub fn main() void {
// String Zig para C
const zig_str: [:0]const u8 = "Olá";
const c_str: [*:0]const u8 = zig_str.ptr;
const len = c.strlen(c_str);
std.debug.print("Tamanho: {d}\n", .{len});
// Ponteiro C para slice Zig
var buffer: [100]u8 = undefined;
const c_ptr: [*]u8 = &buffer;
const zig_slice: []u8 = c_ptr[0..50]; // criar slice com tamanho conhecido
_ = zig_slice;
// void* para tipo específico
const void_ptr: ?*anyopaque = c.malloc(100);
if (void_ptr) |p| {
const typed_ptr: [*]u8 = @ptrCast(@alignCast(p));
typed_ptr[0] = 42;
c.free(p);
}
}
Chamar Funções C a Partir de Zig
Exemplo com libc
const std = @import("std");
const c = @cImport({
@cInclude("math.h");
@cInclude("time.h");
});
pub fn main() void {
// Funções matemáticas
const raiz = c.sqrt(144.0);
std.debug.print("Raiz de 144: {d}\n", .{raiz}); // 12.0
const seno = c.sin(std.math.pi / 2.0);
std.debug.print("sen(π/2): {d}\n", .{seno}); // 1.0
// Tempo
var agora: c.time_t = undefined;
_ = c.time(&agora);
const tm = c.localtime(&agora);
if (tm) |t| {
std.debug.print("Hora: {d}:{d:0>2}:{d:0>2}\n", .{
t.*.tm_hour, t.*.tm_min, t.*.tm_sec,
});
}
}
Callbacks — Passar função Zig para C
const c = @cImport(@cInclude("stdlib.h"));
fn comparar(a: ?*const anyopaque, b: ?*const anyopaque) callconv(.C) c_int {
const val_a: *const i32 = @ptrCast(@alignCast(a));
const val_b: *const i32 = @ptrCast(@alignCast(b));
if (val_a.* < val_b.*) return -1;
if (val_a.* > val_b.*) return 1;
return 0;
}
pub fn main() void {
var nums = [_]i32{ 5, 2, 8, 1, 9, 3 };
// Usar qsort do C com callback Zig
c.qsort(
@ptrCast(&nums),
nums.len,
@sizeOf(i32),
comparar,
);
// nums agora está ordenado: [1, 2, 3, 5, 8, 9]
for (nums) |n| {
std.debug.print("{d} ", .{n});
}
}
Exportar Funções Zig para C
Criar biblioteca usável por C
// lib.zig — exportar funções para C
const std = @import("std");
export fn zig_somar(a: c_int, b: c_int) c_int {
return a + b;
}
export fn zig_processar(dados: [*]u8, tamanho: usize) c_int {
const slice = dados[0..tamanho];
// processar dados...
_ = slice;
return 0; // sucesso
}
// Gerar header C automaticamente com:
// zig build-lib lib.zig -dynamic -femit-h
Header gerado (lib.h):
int zig_somar(int a, int b);
int zig_processar(unsigned char* dados, size_t tamanho);
Configuração no build.zig
Linkar com bibliotecas C
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "meu-app",
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
// Linkar com libc
exe.linkLibC();
// Linkar com bibliotecas do sistema
exe.linkSystemLibrary("SDL2");
exe.linkSystemLibrary("openssl");
exe.linkSystemLibrary("z"); // zlib
// Caminhos de include
exe.addIncludePath(b.path("include"));
exe.addIncludePath(.{ .cwd_relative = "/usr/local/include" });
// Caminhos de biblioteca
exe.addLibraryPath(.{ .cwd_relative = "/usr/local/lib" });
// Compilar arquivos C como parte do projeto
exe.addCSourceFiles(.{
.files = &.{
"src/wrapper.c",
"vendor/lib/util.c",
},
.flags = &.{
"-Wall",
"-O2",
"-std=c11",
},
});
b.installArtifact(exe);
}
Structs C em Zig
// Struct compatível com layout C
const Ponto = extern struct {
x: f64,
y: f64,
z: f64,
};
// Packed struct (sem padding)
const Header = packed struct {
versao: u4,
tipo: u4,
tamanho: u16,
flags: u8,
};
// Usar struct C importada
const c = @cImport(@cInclude("minha_lib.h"));
pub fn main() void {
var ponto = c.criar_ponto(1.0, 2.0, 3.0);
c.mover_ponto(&ponto, 10.0, 0.0, 0.0);
}
Calling Conventions
// Padrão Zig (não compatível com C)
fn funcaoZig() void {}
// Convenção C — necessário para interop
fn funcaoC() callconv(.C) void {}
// Exportar para C
export fn exportada() c_int {
return 0;
}
// Ponteiro de função com convenção C
const FnCallback = *const fn (c_int, c_int) callconv(.C) c_int;
Erros Comuns
// ERRO: Esquecer de linkar libc
// exe.linkLibC(); // necessário se usar @cImport
// ERRO: Tipo errado na conversão
// const x: i32 = valor_c; // use c_int, não i32
// CORRETO
const x: c_int = valor_c;
// ERRO: String Zig não termina em null para C
// const s = "texto"; // pode não ter sentinela 0
// CORRETO: usar literal com sentinela
const s: [:0]const u8 = "texto"; // terminado em 0
Veja Também
- Build System — Configurar linkagem C no build.zig
- Ponteiros — Tipos de ponteiros e conversões
- Strings — Strings Zig vs strings C
- Troubleshooting: Link C — Problemas de linkagem
- FAQ Ecossistema — Bibliotecas C compatíveis com Zig