skills/zig/zig-cinterop/SKILL.md
Zig C interoperability skill. Use when calling C from Zig, calling Zig from C, using @cImport and @cInclude, running translate-c on C headers, defining extern structs and packed structs, matching C ABI types, or building mixed C/Zig projects. Activates on queries about @cImport, @cInclude, translate-c, extern struct, packed struct, Zig C ABI, calling C from Zig, exporting Zig to C, or bindgen equivalents.
npx skillsauth add mohitmishra786/low-level-dev-skills zig-cinteropInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Guide agents through Zig's C interoperability: @cImport/@cInclude for calling C, translate-c for header inspection, extern struct and packed struct for ABI-compatible types, exporting Zig for C consumption, and zig cc for mixed C/Zig builds.
const c = @cImport({
@cInclude("stdio.h");
@cInclude("string.h");
@cInclude("mylib.h");
@cDefine("MY_FEATURE", "1"); // Equivalent to -DMY_FEATURE=1
@cUndef("SOME_MACRO");
});
pub fn main() void {
_ = c.printf("Hello from C: %d\n", @as(c_int, 42));
var buf: [256]u8 = undefined;
_ = c.snprintf(&buf, buf.len, "formatted: %d", @as(c_int, 100));
}
In build.zig:
exe.linkLibC(); // Required when using C functions
exe.addIncludePath(b.path("include/"));
translate-c converts C headers to Zig declarations, letting you see exactly how Zig sees a C API:
# Translate a header file
zig translate-c /usr/include/stdio.h > stdio.zig
# Translate with defines/includes
zig translate-c -I include/ -DFEATURE=1 mylib.h > mylib.zig
# Translate and inspect specific types
zig translate-c mylib.h | grep -A5 "struct MyStruct"
This is Zig's equivalent of bindgen — you use it to understand what Zig generates, then use @cImport directly in code.
| C type | Zig type |
|--------|----------|
| int | c_int |
| unsigned int | c_uint |
| long | c_long |
| unsigned long | c_ulong |
| long long | c_longlong |
| size_t | usize |
| ssize_t | isize |
| char * | [*:0]u8 (null-terminated) |
| const char * | [*:0]const u8 |
| void * | *anyopaque |
| NULL | null |
| bool | bool (C99) or c_int (older) |
| float | f32 |
| double | f64 |
// Passing strings to C
const str = "hello";
_ = c.puts(str); // Zig string literals are [*:0]const u8
// Dynamic strings — need null terminator
var buf: [64:0]u8 = undefined;
const len = std.fmt.bufPrint(buf[0..63], "hello {d}", .{42}) catch unreachable;
buf[len] = 0;
_ = c.puts(&buf);
Use extern struct to match a C struct's memory layout exactly:
// Matches: struct Point { int x; int y; };
const Point = extern struct {
x: c_int,
y: c_int,
};
// Matches: struct Header { uint32_t magic; uint16_t version; uint16_t flags; };
const Header = extern struct {
magic: u32,
version: u16,
flags: u16,
};
// Use with C API
var p = Point{ .x = 10, .y = 20 };
_ = c.draw_point(&p);
// Matches C bitfield: struct { uint8_t flags : 4; uint8_t type : 4; };
const Flags = packed struct(u8) {
mode: u4,
kind: u4,
};
// Packed struct for wire protocols
const IpHeader = packed struct(u32) {
ihl: u4,
version: u4,
tos: u8,
total_length: u16,
};
var h: IpHeader = @bitCast(@as(u32, raw_bytes));
// Export a function callable from C
export fn zig_add(a: c_int, b: c_int) c_int {
return a + b;
}
// Export with specific calling convention
pub fn my_func(x: u32) callconv(.C) u32 {
return x * 2;
}
// Export a struct (use extern struct for C layout)
export const VERSION: c_int = 42;
Generate a C header (manual or with tools):
/* mylib.h */
#ifndef MYLIB_H
#define MYLIB_H
#include <stdint.h>
int zig_add(int a, int b);
uint32_t my_func(uint32_t x);
extern int VERSION;
#endif
// Build Zig as a C-compatible static library
const lib = b.addStaticLibrary(.{
.name = "myzig",
.root_source_file = b.path("src/lib.zig"),
.target = target,
.optimize = optimize,
});
// The C code that uses the Zig library
const c_exe = b.addExecutable(.{
.name = "c_consumer",
.target = target,
.optimize = optimize,
});
c_exe.addCSourceFile(.{
.file = b.path("src/main.c"),
.flags = &.{"-std=c11"},
});
c_exe.linkLibrary(lib);
c_exe.linkLibC();
b.installArtifact(c_exe);
// Forward-declared C struct (opaque)
const FILE = opaque {};
extern fn fopen(path: [*:0]const u8, mode: [*:0]const u8) ?*FILE;
extern fn fclose(file: *FILE) c_int;
extern fn fprintf(file: *FILE, fmt: [*:0]const u8, ...) c_int;
// Opaque handle pattern
const MyHandle = opaque {};
extern fn lib_create() ?*MyHandle;
extern fn lib_destroy(h: *MyHandle) void;
// Call variadic C functions using @call with variadic args
const c = @cImport(@cInclude("stdio.h"));
// printf works directly through @cImport
_ = c.printf("value: %d\n", @as(c_int, 42));
// For custom variadic C functions, use extern with ...
extern fn my_log(level: c_int, fmt: [*:0]const u8, ...) void;
For translate-c output guide and C ABI types reference, see references/translate-c-guide.md.
skills/zig/zig-compiler for zig cc C compilation and basic Zig buildsskills/zig/zig-build-system for build.zig with mixed C/Zig projectsskills/binaries/elf-inspection to verify symbol exports and ABIskills/rust/rust-ffi for comparison with Rust's C FFI approachdevelopment
QEMU/KVM skill for virtualization and kernel development. Use when running qemu-system-x86_64 with KVM, configuring virtio devices, VFIO passthrough, QMP monitor, libvirt, or booting custom kernels. Activates on queries about QEMU, KVM, virtio, VFIO, virsh, virt-install, or -kernel -append.
development
Hardware virtualization internals skill for Intel VT-x and AMD-V. Use when studying VMCS/VMCB, EPT/NPT page tables, VMEXIT handling, APIC virtualization, or building minimal hypervisors. Activates on queries about VMX, SVM, VMCS, EPT, NPT, VMEXIT, or type-1 hypervisor.
testing
Linux containers internals skill for namespaces, cgroups, and OCI. Use when understanding clone/unshare namespaces, cgroups v2 limits, overlayfs, runc, seccomp profiles, capabilities, or escape mitigations. Activates on queries about namespaces, cgroups, overlayfs, runc, seccomp-bpf, OCI spec, or container escape.
tools
Reverse engineering skill for binary analysis. Use when decompiling with Ghidra, analyzing with radare2, scripting RE tools, triaging with strings/file/xxd, or diffing binaries. Activates on queries about Ghidra, radare2, r2, decompiler, Binary Ninja, Diaphora, or stripped binary analysis.