为何系统编程选 Zig 而非 C

Why Zig over C for Systems Programming

C 语言依然是 UNIX 的基石,但我在编写新代码时已转向 Zig。Zig 保留了 C 的简洁与对硬件的直接控制,却解决了 C 最让人头疼的问题:无需 goto 即可优雅处理资源清理,slice 自带长度避免缓冲区溢出,错误处理强制编译器检查,comptime 替代了晦涩的预处理器。更重要的是,Zig 编译器能在 debug 模式下捕获整数溢出等未定义行为。虽然 C 生态更成熟,但 Zig 让系统编程在保持底层控制的同时,显著减少了低级错误。

C 是我最喜欢的编程语言!但我写这篇文章是因为我再也不想用 C 写新代码了。
  1. uecker

    Zig 是一门不错的语言,但那些文章总是拿新语言和那种不使用现代工具的旧式 C 做对比。如果你愿意采用现代工具链和编程风格,列表中的大多数优势在 C 中也能实现:有符号溢出检查可以用 sanitizers;无法忽略的错误可以用 [[nodiscard]];知道自身大小的切片类型可以用可变修饰类型(variably-modified types)或 span 类型。

    Defer 功能很快也会出现在 C 编译器中,不过就我个人而言,我仍然觉得 goto 错误处理更清晰。

    (Rust 在临时内存安全方面确实有优势,但这点并不适用于 Zig。)

  2. variadix

    在使用 C 很长一段时间之后,我最终选择了一种 C++ 方言来进行系统编程。它大部分像 C,我禁用了异常、RTTI 等功能,但我确实使用了模板、重载、方法、lambda 等特性。

    我有自己的对象系统,其中的构造函数方法都返回状态码,这样就不需要异常了;我还有自己的标准库,包含容器、缓冲 I/O、网络、哈希、数学运算、线程、异步等功能。

    C++ 提供了所有必要的特性,让你能够有效地构建自己的语言,而且由于 C++ 支持广泛,你可以使用一流的工具体系。LLM 也让独自构建和测试整个标准库变得容易得多。

  3. pron

    另外,Zig 的表达力至少和 C++ 一样强(但没有那种隐式性和普遍的语言复杂性,这些特性使得审查某些敏感代码变得困难,因为你需要确切地看到执行了哪些操作),并且它在 arena(内存区)支持方面优于 C/C++/Rust。

  4. asveikau

    仅从第一个例子来看:

    struct user *user_new(const char *name, size_t n_groups)

    {

    struct user *u = malloc(sizeof *u);

    if (u == NULL)

    goto fail;

    u->name = strdup(name);

    if (u->name == NULL)

    goto fail_user;

    u->groups = calloc(n_groups, sizeof *u->groups);

    if (u->groups == NULL)

    goto fail_name;

    return u;

    fail_name:

    free(u->name);

    fail_user:

    free(u);

    fail:

    return NULL;

    }

    我觉得你可以比这更好地展示 C 的写法。我喜欢专注于一个清理块,并利用 free(NULL) 是空操作这一事实。

    struct user *user_new(const char *name, size_t n_groups)

    {

    struct user *u = calloc(sizeof *u, 1);

    if (u == NULL)

    goto fail;

    u->name = strdup(name);

    if (u->name == NULL)

    goto fail;

    u->groups = calloc(n_groups, sizeof *u->groups);

    if (u->groups == NULL)

    goto fail;

    return u;

    fail:

    if (u)

    {

    free(u->name);

    free(u->groups);

    }

    free(u);

    return NULL;

    }

    不过要注意,这假设了 calloc(sizeof *u, 1) 会将指针初始化为 NULL。据我所知,假设 NULL 的位模式全为零在技术上违反了标准,但你可能会针对的每个系统都能正常工作。

    如果你遵循“释放 NULL 指针没问题”的模式,你还可以重用 free 函数:[...]

  5. drnick1

    所有这些新语言相对于 C 来说都难以阅读。如果像我一样,你喜欢显式的写法,比如 for (size_t i = 0; i <= n; i++) total += a[i]; 那么所有这些新语言都做不到。

  6. qweqwe14

    Rust 迟早会取代所有这些小众语言。是的,从长远来看,Rust 是 C 和 C++ 的可行替代品。Zig 只是试图做一个中间地带,而我们已经证实这行不通。在 LLM 时代,Zig 相比 Rust 尤其无关紧要。

  7. kombine

    顺便提一下,D 和 Nim 其实几年前就已经拥有这些特性了。

  8. seanw444

    关于我在评论里看到的关于线程的讨论:这真让人沮丧。我们有像 Zig 和 Nim 这样的语言,它们是为了美感和直觉而设计的,但随后却有一堆唱反调的人,只会说“除了 Rust 和 Go 之外的一切语言都因为 LLM 而死了,大势已去,关掉它回家吧”。

    这种能力——通过前所未有的大规模抄袭工厂,以极低的脑力消耗,以创纪录的速度吐出半成品且脆弱的代码——已经将钟摆猛烈地推向了智识主义和人类思维的对立面。这就是人们因 AI 而感到抑郁的原因。这是一场通往无灵魂状态的革命。

同日更多故事

2026-11-13