第1章:为什么是 Rust?
Part1 了解嵌入式rust
第 1 章:为什么是 Rust?——嵌入式开发的新选择#
本章要回答的问题:Rust 在嵌入式领域解决什么问题?它相比 C 有什么优势?本书的讨论范围是什么?
1.1 一个 C 工程师的日常#
如果你是一名嵌入式 C 工程师,下面这些场景你一定不陌生。
野指针:那个”不可能发生”的崩溃#
凌晨两点,产线测试报告发来了:某批次设备在运行 72 小时后随机死机。你打开 Keil,连上 J-Link,看到 HardFault 寄存器指向一个非法地址。追踪了半天,最终发现是一个结构体指针在某个中断回调里被 free 了,而主循环还在用它。
// 中断回调中
void uart_rx_callback(void *ctx) {
msg_t *msg = (msg_t *)ctx;
process(msg);
free(msg); // "我用完了,释放掉"
}
// 主循环中
while (1) {
msg_t *msg = get_pending_msg();
if (msg) {
log(msg->data); // 💥 野指针!msg 已经被中断回调 free 了
send(msg);
}
}c你加了 volatile,加了互斥锁,加了引用计数——但三个月后,另一个同事在另一个模块里又犯了一次同样的错误。
缓冲区溢出:MISRA 检查不出来的逻辑漏洞#
void parse_packet(uint8_t *buf, uint16_t len) {
uint8_t local_buf[64];
// "len 不可能超过 64,协议规定了的"
memcpy(local_buf, buf, len); // 💥 如果固件被篡改了呢?
}cMISRA-C 能检查出你没有做边界检查,但它无法阻止你在另一个函数里”确信” len 不会超限。这种”逻辑上的确信”,正是缓冲区溢出漏洞的温床。
数据竞争:在量产固件中潜伏三年的 bug#
这是一个真实案例的简化版本:
某公司的一款工业网关,使用 STM32F4 + FreeRTOS,运行了三年没有任何问题。直到客户升级了固件,增加了一个新的通信任务,设备开始偶发性地发送错误数据。
排查了两周,最终发现问题出在一个共享的环形缓冲区上:
// 任务 A(高优先级):写入传感器数据
void sensor_task(void *arg) {
while (1) {
read_sensor(&data);
ring_buf_write(&rb, &data, sizeof(data)); // 写 head
}
}
// 任务 B(低优先级):读取并发送
void comm_task(void *arg) {
while (1) {
ring_buf_read(&rb, &data, sizeof(data)); // 读 head
uart_send(&data, sizeof(data));
}
}c问题在于 ring_buf_write 中对 head 指针的更新不是原子的——它是一个 32 位变量,在 Cortex-M4 上虽然是单次写入,但编译器可能重排了 head 更新和数据写入的顺序。在没有内存屏障的情况下,任务 B 可能读到了新的 head 值,但对应的数据还没有写入完成。
这个 bug 之所以潜伏了三年,是因为:
- 旧固件中任务 B 的优先级足够低,调度间隔恰好避开了竞争窗口
- 新固件增加的任务改变了调度时序,让竞争窗口暴露出来
在 Rust 中,这段代码根本编译不通过。 编译器会告诉你:你不能在两个任务之间共享可变状态,除非使用安全的同步原语。这不是运行时检查,不是静态分析工具的”建议”,而是编译错误——你的代码无法生成二进制文件。
这就是 Rust 要解决的核心问题:把”理论上不该出现”的 bug,变成”实际上不可能出现”的 bug。
1.2 嵌入式语言版图#
在讨论 Rust 之前,让我们先看看嵌入式开发中现有的语言选择,以及它们各自的定位。
C 的统治地位与历史原因#
C 在嵌入式领域的统治地位有深厚的历史根基:它诞生于编写 Unix 操作系统,天生就是为系统编程设计的。几乎所有 MCU 的启动代码、板级支持包(BSP)、实时操作系统(RTOS)内核都是用 C 或汇编编写的。厂商提供的 SDK 无一例外地以 C 为第一语言。C 的标准化(C99/C11/C17)和跨平台能力(通过条件编译)让代码可以在不同架构间移植。
C 不会消失,嵌入式 Rust 也从未宣称要”取代”C。本书的目标是给你一个额外的选项——当你的项目对安全和并发有更高要求时,你有 Rust 这个工具。
| 优势 | 说明 |
|---|---|
| 贴近硬件 | 指针、位操作、内存布局完全可控 |
| 零运行时 | 不需要虚拟机、垃圾回收器 |
| 工具链成熟 | 每个芯片厂商都提供 C 编译器 |
| 生态庞大 | CMSIS、HAL、中间件、RTOS 全部是 C |
| 人才储备 | 几乎所有嵌入式工程师都会 C |
| 标准稳定 | C99/C11 之后语言本身变化极小 |
C 的问题同样众所周知:
- 内存安全完全依赖程序员:没有编译期保护,
malloc了忘记free、free了继续使用、越界访问——全靠自觉 - 并发安全没有语言级支持:
volatile不是同步原语,数据竞争是未定义行为 - 抽象能力弱:没有泛型、没有接口、没有模式匹配,复杂逻辑只能靠宏和
void* - 错误处理原始:返回
-1+ 检查errno,容易遗漏
C++ 在嵌入式中的尴尬处境#
C++ 理论上能解决 C 的很多痛点,但在嵌入式领域始终未能普及:
- 运行时开销不确定:异常处理(
try/catch)、RTTI、虚函数表——在资源受限的 MCU 上是不可接受的开销 - 编译产物不可预测:模板实例化、隐式构造/析构、STL 容器的堆分配——你很难精确控制 Flash 和 RAM 占用
- 厂商支持有限:很多 MCU 厂商的 SDK 和示例代码只提供 C 版本
- MISRA C++ 限制严格:安全关键领域对 C++ 特性的限制,使得”现代 C++“的很多优势无法使用
- 学习曲线陡峭:C++ 的复杂度(尤其是模板元编程)让很多嵌入式工程师望而却步
C++ 在嵌入式领域的使用远比 C 少。尽管 C++ 带来了更强的类型系统、RAII(资源获取即初始化)和模板,但它也引入了一套让嵌入式工程师敬而远之的复杂性:异常需要 RTTI 支持,虚函数表占用内存,STL 依赖动态分配。许多嵌入式项目选择”C with classes”——只使用 C++ 的一小部分特性,但这又丧失了 C++ 的完整优势。
更重要的是,C++ 没有从根本上解决内存安全和并发安全的问题。智能指针(std::shared_ptr)和互斥锁(std::mutex)是运行时设施,而非编译期保证。你仍然可以写出悬垂引用的代码,编译器不会报错。
Rust 的不同在于:所有权、借用和生命周期是编译期检查的,没有运行时开销,也不需要垃圾回收。这使得 Rust 在资源和安全性约束都苛刻的嵌入式领域,具备了独特的竞争力。
MicroPython / Lua 等脚本语言的适用边界#
脚本语言在嵌入式领域占有一席之地——MicroPython 让快速原型成为可能,Lua 在 NodeMCU 上驱动着无数 IoT 实验,JerryScript 让 JavaScript 跑在资源受限的设备上。但它们共享一个根本限制:解释执行,边界非常清晰:
- 适用:快速原型验证、教育、对性能要求极低的场景(如简单的传感器读取 + WiFi 上报)
- 不适用:硬实时控制、资源受限平台(< 256KB Flash)、安全关键应用、量产产品
脚本语言的根本限制是运行时开销和不确定性——垃圾回收的暂停时间、解释执行的性能损失、动态类型的运行时错误,这些都与嵌入式的核心需求相矛盾。解释器的开销意味着更高的功耗、更大的内存占用和更低的实时性。它们适合非关键、容忍延迟的应用——比如教育、原型验证、简单的数据采集。但当你需要 100 μs 级别的中断响应,或者固件必须跑在仅有 16 KB RAM 的 MCU 上时,脚本语言就碰壁了。
Rust 的定位:系统级语言,但更安全x |#
Rust 的定位非常明确:与 C/C++ 同一层级的系统编程语言,但在编译期消除内存安全和并发安全的错误。
┌─────────────────────────────────────────────────────┐
│ 应用层语言 │
│ Python / JavaScript / Go / Java │
│ (需要运行时、GC、虚拟机) │
├─────────────────────────────────────────────────────┤
│ 系统级语言 │
│ C / C++ / Rust / Zig │
│ (直接操作硬件、无运行时、确定性行为) │
├─────────────────────────────────────────────────────┤
│ 硬件描述语言 │
│ Verilog / VHDL / Chisel │
│ (描述数字电路) │
└─────────────────────────────────────────────────────┘plaintextRust 与 C 在同一层级,意味着:
- 可以直接操作寄存器和内存地址
- 没有垃圾回收器,没有运行时
- 编译产物是原生机器码,体积和性能与 C 相当
- 可以在裸机上运行,不需要操作系统
但 Rust 比 C 多了编译期的安全保障——这是后续章节会反复展开的核心主题。
1.3 Rust 的核心优势#
对于嵌入式工程师,Rust 有三个核心理念直接对应我们的日常痛点。
内存安全:不需要 malloc/free,也没有悬垂指针#
C 工程师最熟悉的两个噩梦是:忘记 free(内存泄漏)和过早 free(悬垂指针)。Rust 通过所有权系统彻底消灭了这两个问题:每个值有且仅有一个所有者,所有者离开作用域时值自动释放。没有 malloc 和 free 的显式调用,编译器在编译期插入了精确的释放逻辑。
但这不仅仅是堆内存的问题。嵌入式大量使用静态分配和栈分配。Rust 的所有权同样保护引用:编译器保证任何引用都不会超过它所指向的数据的生命周期。这意味着你无法创建一个引用,让它指向已经被释放或重新分配的变量——这是 C 中”悬垂指针”的源头。
并发安全:编译器阻止数据竞争#
“数据竞争”是指两个线程/任务同时访问同一内存位置,且至少有一个是写操作,且没有同步机制。数据竞争是未定义行为,在 C 中是静态分析工具的查杀对象。Rust 通过 Send 和 Sync trait(特性)在编译期检查:一个类型能否安全地在线程间传递?能否安全地被多个线程共享引用?如果你试图在没有互斥锁的情况下跨任务修改共享变量,Rust 编译器会直接拒绝编译。
对于裸机开发,并发通常发生在中断和主循环之间,以及不同优先级的中断之间。Rust 的 Mutex 和原子操作被设计为即使在 no_std 环境下也能安全使用。
零成本抽象:高级语法,底层性能#
C 工程师对”抽象”总是警惕的。C++ 的虚函数有 vtable 开销,脚本语言的动态类型有运行时判断成本。Rust 的哲学是:你不需要为不使用的特性付出性能代价,你使用的抽象在编译后与手写的底层代码一样高效。
这意味着你可以用迭代器、闭包、泛型、trait 等高级工具编写清晰的代码,而编译器通过单态化(monomorphization)和激进的内联优化,生成和精心手写的 C 代码几乎完全相同的机器指令。第 4 章会通过反汇编对比直观证明这一点。
与 C 的互操作性#
Rust 不是孤岛。通过外部函数接口(FFI),Rust 可以直接调用 C 函数,C 也可以调用 Rust 函数。这意味着你可以:
在现有 C 项目中逐步引入 Rust 模块
复用成熟的 C 库(如硬件抽象层、协议栈)
将 Rust 编译为静态库,链接到现有的 C 固件中
乐鑫(Espressif)的 esp-idf 项目就是典型的混合编程:底层 C 框架,上层 Rust 应用逻辑。
1.4 两种 Rust:std 环境与 no_std 环境#
什么是 no_std?为什么嵌入式需要它?#
这是 C 工程师理解 Rust 嵌入式开发的第一个”分水岭”。
在你的 Linux 或 Windows 机器上编写 Rust 程序时,你可以使用 Rust 的标准库(std)。std 提供了丰富且可移植的 API:文件系统操作、网络通信、动态内存分配(Box、Vec)、多线程(std::thread)等。这些 API 假设底层有操作系统的支持——比如内存分配器、线程调度器、文件系统驱动。
但在大多数微控制器上,没有操作系统。没有堆分配器(除非你手动实现),没有线程,没有文件系统。你不能假设 println! 能工作,因为根本没有标准输出。
这就是 no_std 环境。Rust 标准库被设计为分层结构:
core:最底层,不依赖任何操作系统。提供了基础类型、Option、Result、迭代器、原子操作、Future trait 等。任何 Rust 程序都可以使用 core。
alloc:依赖一个全局分配器,提供了需要动态内存的类型,如 Box、Vec、String、Arc。在嵌入式裸机中,如果你实现了一个堆分配器,就可以使用 alloc。
std:完整标准库,依赖操作系统。提供文件 I/O、网络、线程、时间等。
本书的全部内容都基于 no_std 环境,大部分时候我们只使用 core 和精选的嵌入式 crate(库),不依赖堆分配。这与你在 Linux 上写 Rust 完全不同,但很接近你在 C 裸机开发中的体验——没有 malloc,没有 printf(除非你自己实现),一切都需要精确控制。
C 工程师可以这样类比:
core 就像 C 语言本身的语法和基本类型(int、char、struct)
alloc 就像你实现了 malloc 后可以使用动态内存
std 就像你在 Linux 应用开发中可以使用 glibc 的所有功能
本书的目标是让你在 core 的基础上,借助嵌入式 Rust 生态(HAL、Embassy 等),构建安全且高效的裸机应用。
core、alloc、std 三层标准库#
Rust 的标准库实际上是分层的:
┌─────────────────────────────────────────┐
│ std(标准库) │
│ 文件系统、网络、线程、println!、Vec... │
│ 需要操作系统支持 │
├─────────────────────────────────────────┤
│ alloc(分配库) │
│ Box、Vec、String、Rc... │
│ 需要堆内存分配器(可以自行实现) │
├─────────────────────────────────────────┤
│ core(核心库) │
│ 基本类型、trait、迭代器、Option、Result │
│ 原子操作、格式化、panic 机制 │
│ 不依赖任何操作系统,纯语言层面 │
└─────────────────────────────────────────┘plaintextcore:永远可用,不依赖任何外部服务。嵌入式 Rust 的基础。alloc:需要堆分配器。在 RAM 充足的 MCU 上可以使用(如 STM32F4 有 192KB RAM)。std:需要完整的操作系统。嵌入式裸机开发中不使用。
与 C 的”裸机 vs Linux 应用”类比#
| 概念 | C 的世界 | Rust 的世界 |
|---|---|---|
| 裸机开发 | 不链接 glibc,直接用 CMSIS/寄存器 | #![no_std],只用 core |
| Linux 应用 | 链接 glibc,用 printf、malloc、pthread | 链接 std,用 println!、Vec、thread |
| 中间地带 | Newlib(精简 C 库) | alloc(有堆但无 OS) |
如果你写过裸机 C(不依赖 Linux 应用层 API),那么 no_std Rust 对你来说会非常自然——它本质上就是”不链接标准库的 Rust”,和你”不链接 glibc 的 C”是同一个思路。
1.5 Rust 在嵌入式领域的采用情况(2026 年现状)#
如果你还在犹豫”Rust 嵌入式是不是太早了”,让我们看看 2026 年的行业现状。
行业数据:Rust 首次进入 TIOBE 前十#
2026 年 7 月,TIOBE 编程社区指数公布了最新排行榜:Rust 以 1.34% 的评分历史性地跻身第 10 位,这是 Rust 诞生 16 年以来首次进入 TIOBE 前十。
TIOBE CEO Paul Jansen 在评论中指出:“Rust 日益增长的流行度很大程度上归功于它在生成极快代码的同时,对内存安全性的高度重视。它被广泛认为是 C 和 C++ 的直接竞争对手。”
就在两个月前(2026 年 4 月),Paul Jansen 还曾公开表示 Rust 的增长可能进入了”平台期”。但 6 月 Rust 冲至第 12 名,7 月直接跃入前十——他不得不收回判断,在榜单标题中写道:“关于 Rust 进入平台期的说法,或许为时尚早。”
对嵌入式工程师的意义:TIOBE 前十意味着 Rust 不再是”小众实验语言”,而是进入了主流视野。招聘市场、培训体系、企业技术选型都会随之调整。
全球超过六成科技企业已将 Rust 纳入技术路线图#
多项行业调查显示,全球超过 60% 的科技企业已将 Rust 纳入其技术路线图或正在评估中。从微软(Windows 内核组件 Rust 化)、谷歌(Android 系统底层)、亚马逊(AWS 基础设施)到 Cloudflare(边缘计算),Rust 正在从”可选”变为”必选”。
在嵌入式领域,这一趋势同样明显:
- 英飞凌(Infineon)与 HighTec 合作,为 AURIX™ 微控制器提供 ISO 26262 认证的 Rust 编译器
- 意法半导体(ST)的 STM32 生态中,社区驱动的 Rust HAL 已覆盖几乎所有主流系列
- Nordic Semiconductor 的 nRF 系列是 Rust 嵌入式生态最成熟的无线平台之一
Ferrocene 通过 ISO 26262 ASIL D 认证——安全关键领域的里程碑#
Ferrocene 是由 Ferrous Systems 和 AdaCore 联合开发的 Rust 编译器工具链,专为安全关键和关键任务系统设计。2025-2026 年间,Ferrocene 通过了 ISO 26262 ASIL D 认证——这是汽车功能安全标准中的最高安全等级。
ASIL D 意味着什么?
- 适用于制动、转向、动力控制等关乎人命的系统
- 随机硬件失效率需低于 10⁻⁸/h
- 对开发流程、验证方法、证据文件的要求极其严苛
这是 Rust 工具链首次获得汽车功能安全最高等级认证,标志着 Rust 正式具备了进入安全关键领域的资格。对于汽车电子工程师来说,这意味着:
你不再需要为了通过功能安全认证而被迫使用 C——Rust 现在是一个合规的选择。
乐鑫(Espressif)将 Rust 提升为官方一等 SDK#
乐鑫科技(ESP32 系列的制造商)做出了一个在嵌入式行业具有标杆意义的决定:将 Rust 提升为官方一等公民 SDK,与传统的 ESP-IDF(C/C++)并列。
具体表现为:
esp-hal:乐鑫官方维护的 Rust HAL,覆盖 ESP32/S2/S3/C3/C6/H2 全系列- Embassy 作为默认异步框架:
esp-hal原生集成 Embassy,提供异步外设驱动 esp-wifi:官方 Rust WiFi 驱动,基于 Embassy 异步模型- 官方文档和示例:与 ESP-IDF 文档同等维护力度
这是第一家将 Rust 提升到与 C/C++ 同等地位的主流 MCU 厂商。对于 IoT 开发者来说,这意味着你可以用 Rust + Embassy 开发 ESP32 产品,并获得官方级别的支持。
Rust 1.94:6 倍编译速度提升 + 29 项 RISC-V 特性稳定化#
2026 年 3 月,Rust 1.94 正式发布,带来了两个对嵌入式开发者影响深远的改进:
1. 编译速度提升最高 6 倍
Rust 1.94 将并行编译(Parallel Compilation)设为默认开启,并引入了新的 “Eddy” 编译后端架构。对于大型嵌入式项目(依赖数十个 crate),编译时间从原来的十几分钟缩短到两三分钟。
这直接解决了 Rust 嵌入式开发最大的体验痛点之一——“喝杯咖啡等编译”的日子正在成为历史。
2. 29 项 RISC-V 架构特性稳定化
Rust 1.94 稳定了 29 项 RISC-V 相关的 target feature,包括:
- 原子操作扩展(A 扩展)
- 压缩指令扩展(C 扩展)
- 乘除法扩展(M 扩展)
- 浮点扩展(F/D 扩展)
- 向量扩展(V 扩展)的部分支持
这意味着 Rust 对 RISC-V 平台的支持从”实验性”进入了”生产级”。对于使用 ESP32-C3/C6/H2(RISC-V 内核)的开发者来说,这是一个重大利好。
Linux 内核中的 Rust 驱动(从实验到生产)#
2025 年底,在日本东京举行的 Linux Kernel Maintainer Summit 上,Rust for Linux 项目负责人 Miguel Ojeda 正式宣布:
“实验已经完成。Rust 将会继续存在。”
这标志着 Rust 从 Linux 内核的”实验性语言”正式升级为永久核心语言,与 C 并列。2026 年 4 月发布的 Linux 7.0 内核中,Rust 驱动框架已全面稳定化。
虽然本书聚焦裸机嵌入式开发,但 Linux 内核的选择具有强烈的信号意义:如果 Linux 内核都信任 Rust 的安全性,那么嵌入式 MCU 上的 Rust 开发还有什么好犹豫的呢?
1.6 本书的边界与阅读前提#
本书覆盖#
| 主题 | 说明 |
|---|---|
| Rust 核心语法 | 面向 C 工程师的最小必要知识集(第 2 章) |
| 裸机 Rust 工程 | 从创建项目到烧录调试的完整流程(第 3 章) |
| 零成本抽象 | 类型状态、单例模式、unsafe 的正确使用(第 4 章) |
| 并发基础 | 抢占式 vs 协作式、临界区、原子操作(第 5 章) |
| 生态层次 | embedded-hal、PAC/HAL/驱动分层(第 6 章) |
| Embassy 框架 | 运行时、任务、通信、定时器(第 7-10 章,全书核心) |
| Embassy 生态 | USB、网络、Bootloader、蓝牙(第 11 章) |
| 工具链深度 | 链接脚本、调试链路、defmt 日志(第 12 章) |
| 多平台移植 | STM32/nRF/RP2040/ESP32 的差异与移植(第 13 章) |
| 性能优化 | 体积控制、运行时开销、常见陷阱(第 14 章) |
| 生态全景 | 库推荐、安全关键、迁移策略(第 15 章) |
本书不覆盖#
- Linux 应用层 Rust:
std环境下的 Rust 编程(Web、CLI、系统工具) - Rust 编译器原理:借用检查器的实现细节、MIR/HIR 等内部表示
- Rust 异步运行时的通用理论:Tokio、async-std 等服务器端异步框架
- 完整的 Rust 语言教程:本书只讲嵌入式需要的部分
阅读前提#
必须具备:
- 熟悉 C 语言(指针、结构体、位操作、函数指针)
- 了解基本嵌入式概念(寄存器、中断、外设、Flash/RAM)
- 有至少一个 MCU 项目的开发经验(哪怕是点灯)
不要求:
- 预先掌握 Rust(第 2 章会从零速成)
- 了解异步编程(第 5、7 章会从概念讲起)
- 有 RTOS 经验(第 5 章会对比讲解)
主力平台说明#
全书代码示例以 STM32 为主力平台(C 工程师最熟悉),RP2040/RP2350 作为辅助对比平台。选择 STM32 的理由:
- 读者群最大:绝大多数 C 嵌入式工程师都有 STM32 经验
- Embassy 支持最成熟:
embassy-stm32覆盖 F0/F1/F2/F3/F4/F7/H7/L0/L1/L4/L5/G0/G4/U5/WB/WL 全系列 - 调试工具链完善:ST-Link + probe-rs 开箱即用
- 与 C 的对比最直观:同一颗芯片,C 的 HAL 库 vs Rust 的 Embassy HAL
1.7 本章小结与全书预览#
本章要点回顾#
- C 的痛点是真实的:野指针、缓冲区溢出、数据竞争——这些问题不是”理论上存在”,而是每天都在产线上发生
- Rust 的定位是系统级语言:与 C 同层级,无运行时,直接操作硬件,但多了编译期安全保障
no_std是嵌入式 Rust 的基础:不链接标准库,只用core,与裸机 C 的思路一致- 2026 年是嵌入式 Rust 的转折点:TIOBE 前十、Ferrocene ASIL D 认证、乐鑫官方一等支持、Linux 内核永久采用——所有信号都指向同一个方向
- 本书的路径:Rust 速成 → 裸机工程 → 零成本抽象 → 并发基础 → Embassy 核心 → 工程实践
全书预览#
Part 1:通用基础(第 1-6 章)
"为什么用 Rust?Rust 怎么写?裸机工程怎么搭?"
│
▼
Part 2:Embassy 核心编程(第 7-11 章)
"Embassy 是什么?怎么用?原理是什么?生态有哪些?"
│
▼
Part 3:工程实践与生态全景(第 12-15 章)
"工具链怎么工作?怎么移植?怎么优化?生态全貌是什么?"plaintext下一步#
在第 2 章中,我们将用一章的篇幅完成 Rust 的”C 工程师速成”。这不是完整的 Rust 教程——我们只讲后续章节会用到的 20% 语法,用 C 的类比帮助你快速建立映射。