mcpField
Z
zig-cinterop

zig-cinterop

github.com/mohitmishra786开发269492 次安装18 周前更新
代码仓库

关于 zig-cinterop

zig-cinterop 为处理 Zig 与 C 互操作的 Agent 提供指导,涵盖导入和导出函数、ABI 类型布局、头文件转换及混合语言构建。

主要功能

  1. 01使用 @cImport 导入 C 声明
  2. 02用 translate-c 检查头文件
  3. 03映射 C 类型与 ABI 布局
  4. 04向 C 导出 Zig 函数
  5. 05构建混合 C/Zig 项目

适用场景

  1. 01在 Zig 中调用 C 库
  2. 02检查 Zig 如何转换 C 头文件
  3. 03匹配 C 结构体和位域布局
  4. 04向 C 调用方提供 Zig 函数

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mohitmishra786/low-level-dev-skills --skill zig-cinterop

安装后在 Claude Code 中输入/zig-cinterop确认已加载。

附带文件references/translate-c-guide.md

详细介绍

Zig C 互操作

目的

指导 Agent 使用 Zig 的 C 互操作功能:使用 @cImport/@cInclude 调用 C、使用 translate-c 检查头文件、使用 extern struct 和 packed struct 定义 ABI 兼容类型、导出 Zig 供 C 使用,以及使用 zig cc 构建混合 C/Zig 项目。

触发条件

  • “如何从 Zig 调用 C 函数?”
  • “如何使用 @cImport 和 @cInclude?”
  • “如何导出 Zig 函数供 C 调用?”
  • “如何定义与 C 结构体匹配的结构体?”
  • “translate-c 有什么作用?”
  • “如何构建混合 C 和 Zig 项目?”

工作流

1. 使用 @cImport 从 Zig 调用 C
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));
}

在 build.zig 中:

exe.linkLibC();  // Required when using C functions
exe.addIncludePath(b.path("include/"));
2. translate-c — 检查 C 头文件的转换结果

translate-c 会将 C 头文件转换为 Zig 声明,让你准确了解 Zig 如何看待 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"

这相当于 Zig 版的 bindgen——使用它来了解 Zig 生成的内容,然后在代码中直接使用 @cImport。

3. C 类型映射
C 类型Zig 类型
intc_int
unsigned intc_uint
longc_long
unsigned longc_ulong
long longc_longlong
size_tusize
ssize_tisize
char *[*:0]u8(以 null 结尾)
const char *[*:0]const u8
void **anyopaque
NULLnull
boolbool(C99)或 c_int(较早版本)
floatf32
doublef64
// 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 兼容结构体

使用 extern struct,使其内存布局与 C 结构体完全一致:

// 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 — 位级布局
// 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. 将 Zig 导出给 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;

生成 C 头文件(手动生成或使用工具):

/* 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. 在 build.zig 中从 C 调用 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. 不透明类型和前向声明
// 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. 可变参数函数
// 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;

有关 translate-c 输出指南和 C ABI 类型参考,请参阅 references/translate-c-guide.md。

相关技能

  • 使用 skills/zig/zig-compiler 进行 zig cc C 编译和基本 Zig 构建
  • 使用 skills/zig/zig-build-system 通过 build.zig 构建混合 C/Zig 项目
  • 使用 skills/binaries/elf-inspection 验证符号导出和 ABI
  • 使用 skills/rust/rust-ffi 对比 Rust 的 C FFI 方案

评论

支持 Markdown