28、C语言与其他语言的对比:C与Rust、Go、Zig在系统编程领域的比较

系统编程这个领域,C语言已经统治了快五十年。说实话,这个地位挺吓人的。

但最近十年,Rust、Go、Zig这些新语言纷纷冒出来,都号称要「取代C」。我一开始也觉得是噱头,直到自己亲手用它们写了几个项目……嗯,有些地方确实让人眼前一亮。

今天咱们就掰开揉碎,看看C跟这几个后起之秀到底差在哪、好在哪。

一、内存安全:C的阿克琉斯之踵

C语言最大的痛,就是内存安全。我在项目中遇到过无数次段错误,查起来真是要命。你想想看,一个野指针、一次缓冲区溢出,就能让整个系统崩溃。

Rust 在这方面做得最绝。它搞了一套所有权(Ownership)和借用(Borrowing)机制,编译期就把内存问题全堵死了。

// Rust 示例:所有权系统
fn main() {
    let s1 = String::from("hello");
    let s2 = s1;  // s1 的所有权转移给了 s2
    // println!("{}", s1);  // 编译错误!s1 已失效
}

我第一次写Rust时,被编译器骂得狗血淋头。但习惯了之后,确实再也没跑出过内存泄漏。代价是什么?学习曲线陡得像悬崖。

Go 选择了另一条路——垃圾回收(GC)。你只管分配内存,Go后台自动帮你回收。简单是简单,但GC带来的停顿,在实时系统里是致命的。

Zig 则更接近C的思路:没有GC,没有所有权,全靠开发者自己管理。但它提供了编译时的安全检查,比如数组越界检查。

我的看法:

如果你写的是航天、医疗设备这类「死都不能出bug」的系统,Rust是更好的选择。但如果你像我一样,经常写嵌入式驱动、操作系统内核,C的灵活性和可控性依然无可替代。

二、并发模型:谁更懂多核?

现在的CPU都是多核的,并发编程成了必修课。C语言在这方面……嗯,基本靠pthreads库,你得自己管锁、管条件变量、管死锁预防。

Go 的goroutine是我用过最爽的并发模型。你写个 go func() 就启动了一个轻量级线程,底层由Go运行时调度。

// Go 示例:goroutine
func main() {
    ch := make(chan int)
    go func() {
        ch <- 42
    }()
    fmt.Println(<-ch)
}

我有个项目,用C写了个多线程下载器,光锁就调了两天。后来用Go重写,半天搞定。但Go的goroutine有个坑:它默认的栈很小(几KB),但如果你不小心写了死循环,整个程序就卡死了。

Rust 的并发模型更安全。它通过Send和Sync trait,在编译期就防止了数据竞争。代价是写起来比较绕,尤其是生命周期标注,能把人绕晕。

Zig 目前没有内置的并发模型,它更倾向于让你用操作系统原生的线程和原子操作。说白了,Zig觉得「并发是库的事,不是语言的事」。

语言 并发模型 安全性 学习成本
C pthreads + 手动锁 低(容易死锁)
Go goroutine + channel 中(GC停顿)
Rust 所有权 + Send/Sync 高(编译期检查) 极高
Zig 原生线程 + 原子操作 中(依赖开发者)

三、编译速度与工具链

C语言的编译速度,说实话,挺慢的。尤其是大型项目,make一下能喝杯咖啡。我有个嵌入式项目,全量编译要15分钟。

Go 的编译速度是出了名的快。它没有头文件,没有复杂的模板展开,编译一个中型项目也就几秒钟。

Rust 的编译速度……嗯,是它的短板。因为要做大量的静态分析和泛型单态化,编译时间经常以分钟计。我有个Rust项目,改一行代码,重新编译要等40秒。

Zig 在这方面做得不错。它直接调用系统自带的C编译器(如clang),而且没有隐式的依赖分析,编译速度比C还快一点。

小技巧:

如果你在C项目里用CMake,可以试试Zig的build系统。它能直接编译C代码,而且速度更快。我最近就在这么干,效果不错。

四、与C的互操作性

这一点很关键。系统编程不是从零开始,你得跟现有的C库、C代码打交道。

Rust 提供了FFI(外部函数接口),可以直接调用C函数。但有个问题:Rust的字符串不是以'\0'结尾的,传参时得手动转换。

// Rust 调用 C 的 printf
extern "C" {
    fn printf(format: *const u8, ...) -> i32;
}

fn main() {
    let msg = b"Hello from Rust\0";
    unsafe {
        printf(msg.as_ptr());
    }
}

Go 的cgo机制也能调用C代码,但性能开销比较大。每次cgo调用都要切换栈,频繁调用时性能下降明显。

Zig 在这方面做得最自然。它可以直接编译C代码,甚至能直接使用C的头文件。我试过把一段C代码直接粘贴到Zig文件里,稍微改改就能跑。

注意:

Zig虽然能直接编译C代码,但C的宏定义、条件编译这些特性,在Zig里需要手动处理。我曾经被一个复杂的宏定义坑了半天,最后还是老老实实手动翻译了。

五、知识体系对比图

下面这张图,是我根据多年经验总结的。它展示了C、Rust、Go、Zig在系统编程核心维度上的定位。

系统编程语言核心维度对比 高性能 · 高安全 Rust 所有权系统、零成本抽象 适合:系统工具、WebAssembly 高性能 · 低安全 C / Zig 手动内存管理、极致控制 适合:嵌入式、操作系统内核 低性能 · 低安全 (传统脚本语言) Python、Ruby等 不适合系统编程 低性能 · 高安全 Go 垃圾回收、goroutine 适合:网络服务、CLI工具 性能 → 安全性 →

从图上可以看得很清楚:C和Zig在「高性能、低安全」这个象限,Rust在「高性能、高安全」,Go在「低性能、高安全」。没有完美的语言,只有适合的场景。

六、我的选择建议

说了这么多,到底该用哪个?我个人的经验是这样的:

  • 写操作系统内核、嵌入式驱动:首选C。Zig可以作为备选,但生态还不够成熟。
  • 写网络服务、CLI工具:Go是最舒服的。开发效率高,部署简单。
  • 写安全敏感的系统组件:比如浏览器引擎、加密库,Rust是更好的选择。
  • 写性能极致、又不想放弃安全:可以试试Zig。它比C安全,又比Rust简单。

最后说一句:

语言只是工具。我见过用C写出优雅代码的人,也见过用Rust写出屎山的人。关键还是看你对底层原理的理解,以及……嗯,写代码的习惯。

公众号:蓝海资料掘金营,微信deep3321