/zig-cinterop
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,
$ npx -y skills add mohitmishra786/low-level-dev-skills --skill zig-cinterop --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/zig-cinterop
Context preview
The summary Claude sees to decide when to auto-load this skill.
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,
SKILL.md
zig-cinterop.SKILL.mdname: zig-cinterop
description: 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.
Zig C Interop
Purpose
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.
Triggers
- "How do I call a C function from Zig?"
- "How do I use @cImport and @cInclude?"
- "How do I export Zig functions to be called from C?"
- "How do I define a struct that matches a C struct?"
- "What does translate-c do?"
- "How do I build a mixed C and Zig project?"
Workflow
1. Calling C from Zig with @cImport
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/"));2. translate-c — inspect C header translation
`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.
3. C type mapping
| 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);4. extern struct — ABI-compatible structs
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);5. packed struct — bit-level layout
// 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));6. Exporting Zig to C
// 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
7. Calling Zig from C in build.zig
// 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);8. Opaque types and forward declarations
// 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;9. Variadic functions
// 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](references/translate-c-guide.md).
Related skills
- Use `skills/zig/zig-compiler` for `zig cc` C compilation and basic Zig builds
- Use `skills/zig/zig-build-system` for `build.zig` with mixed C/Zig projects
- Use `skills/binaries/elf-inspection` to verify symbol exports and A
Read more
name: zig-cinterop description: 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.
Zig C Interop
Purpose
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.
Triggers
- "How do I call a C function from Zig?"
- "How do I use @cImport and @cInclude?"
- "How do I export Zig functions to be called from C?"
- "How do I define a struct that matches a C struct?"
- "What does translate-c do?"
- "How do I build a mixed C and Zig project?"
Workflow
1. Calling C from Zig with @cImport
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/"));2. translate-c — inspect C header translation
`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.
3. C type mapping
| 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);4. extern struct — ABI-compatible structs
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);5. packed struct — bit-level layout
// 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));6. Exporting Zig to C
// 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
7. Calling Zig from C in build.zig
// 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);8. Opaque types and forward declarations
// 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;9. Variadic functions
// 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](references/translate-c-guide.md).
Related skills
- Use `skills/zig/zig-compiler` for `zig cc` C compilation and basic Zig builds
- Use `skills/zig/zig-build-system` for `build.zig` with mixed C/Zig projects
- Use `skills/binaries/elf-inspection` to verify symbol exports and A
A curated suite of AI agent skills for systems and low-level programming — C/C++, Rust, Zig, GPU, bare-metal firmware, Linux kernel/driver development, computer architecture, compiler internals, HPC, and more.
Repo: mohitmishra786/low-level-dev-skills
Other skills on low-level-dev-skills.
- /custom-allocators
Custom allocator skill for memory allocation strategies. Use when implementing pool/slab/arena allocators, tuning jemalloc/mimalloc, writing Rust GlobalAlloc, or benchmarking allocator performance. Activates on queries about jemalloc, mimalloc, tcmalloc, arena allocator,
Open skill - /numa-programming
NUMA programming skill for multi-socket memory locality. Use when detecting NUMA topology, binding processes with numactl, using libnuma API, building NUMA-aware data structures, or measuring remote access penalties. Activates on queries about numactl, libnuma, NUMA topology,
Open skill - /af-xdp
AF_XDP skill for high-performance XDP sockets. Use when creating AF_XDP sockets, configuring UMEM and XSK rings, XDP_REDIRECT programs, copy vs zero-copy mode, or comparing with DPDK. Activates on queries about AF_XDP, xsk_umem, XDP_REDIRECT, libbpf xsk, or zero-copy XDP.
Open skill - /dpdk
DPDK skill for userspace packet I/O. Use when initializing EAL, configuring PMD drivers, using mbuf pools and rte_ring, setting up huge pages, RSS, or testpmd validation. Activates on queries about DPDK, EAL, rte_eth_rx_burst, hugepages, PMD, or testpmd.
Open skill - /io-uring
io_uring skill for Linux async I/O. Use when building high-performance servers with liburing, multi-shot operations, provided buffers, fixed files, zero-copy send, or tokio-uring. Activates on queries about io_uring, SQE/CQE, liburing, IORING_OP_PROVIDE_BUFFERS, or io_uring vs
Open skill - /adc-dac-baremetal
Bare-metal ADC and DAC skill. Use when configuring analog sampling, DMA-driven ADC, calibration, or DAC output on MCUs. Activates on queries about ADC bare-metal, sampling time, DMA ADC, or DAC channel setup.
Open skill

