rust-no-std
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseRust no_std
Rust no_std
Purpose
用途
Guide agents through Rust development: what and provide vs , implementing custom global allocators, panic handler selection for embedded targets, and strategies for testing crates on the host machine.
#![no_std]coreallocstdno_std引导开发者完成 Rust开发:讲解、与的区别,实现自定义全局分配器,为嵌入式目标选择panic处理器,以及在主机环境测试 crate的策略。
#![no_std]coreallocstdno_stdTriggers
触发场景
- "How do I write a #![no_std] Rust crate?"
- "What's the difference between core, alloc, and std in Rust?"
- "How do I use Vec and String in a no_std environment?"
- "How do I implement a global allocator in Rust?"
- "How do I handle panics in no_std Rust?"
- "How do I test a no_std crate without hardware?"
- "如何编写Rust crate?"
#![no_std] - "Rust中的core、alloc和std有什么区别?"
- "如何在no_std环境中使用Vec和String?"
- "如何在Rust中实现全局分配器?"
- "如何处理no_std Rust中的panic?"
- "如何在没有硬件的情况下测试no_std crate?"
Workflow
工作流程
1. no_std crate structure
1. no_std crate结构
rust
// src/lib.rs
#![no_std]
// core is always available (no OS needed)
use core::fmt;
use core::mem;
use core::slice;
// alloc: heap collections — requires a global allocator
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::{vec::Vec, string::String, boxed::Box, format};
pub fn add(a: u32, b: u32) -> u32 {
a + b
}toml
undefinedrust
// src/lib.rs
#![no_std]
// core始终可用(无需操作系统)
use core::fmt;
use core::mem;
use core::slice;
// alloc:堆集合 — 需要全局分配器
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::{vec::Vec, string::String, boxed::Box, format};
pub fn add(a: u32, b: u32) -> u32 {
a + b
}toml
undefinedCargo.toml
Cargo.toml
[features]
default = []
alloc = [] # opt-in to heap allocation
[dependencies]
[features]
default = []
alloc = [] // 可选启用堆分配
[dependencies]
// 仅使用兼容no_std的依赖
undefinedno_std-compatible dependencies only
2. core vs alloc vs std
undefined| Crate | 需要操作系统 | 需要堆 | 提供功能 |
|---|---|---|---|
| 否 | 否 | 基础类型、trait、迭代器、格式化、内存操作、指针、切片、Option、Result |
| 否 | 是(需分配器) | Vec、String、Box、Arc、Rc、HashMap(需要全局分配器) |
| 是 | 是 | 包含core和alloc的所有内容 + 操作系统API(线程、文件、套接字、环境变量) |
stdcoreallocstduse std::fmtuse core::fmt仅可用的功能(无需堆、无需操作系统):
corerust
// 这些在no_std环境中可正常使用:
core::fmt::Write // write!宏对应的trait
core::iter // 迭代器
core::ops // 运算符(+、-、*、Deref等)
core::option::Option
core::result::Result
core::mem::{size_of, align_of, swap, replace}
core::ptr::{read, write, null, NonNull}
core::slice, core::str
core::sync::atomic // 原子类型
core::cell::{Cell, UnsafeCell, RefCell}
core::cmp, core::convert, core::clone, core::default
core::num // 数值转换
core::panic::PanicInfo // 用于panic处理器2. core vs alloc vs std
3. 自定义全局分配器
| Crate | Requires OS | Requires heap | Provides |
|---|---|---|---|
| No | No | Primitives, traits, iter, fmt, mem, ptr, slice, option, result |
| No | Yes (allocator) | Vec, String, Box, Arc, Rc, HashMap (requires global allocator) |
| Yes | Yes | All of core + alloc + OS APIs (threads, files, sockets, env) |
stdcoreallocuse std::fmtuse core::fmtstdWhat's available in only (no heap, no OS):
corerust
// These work in no_std:
core::fmt::Write // trait for write! macro
core::iter // iterators
core::ops // operators (+, -, *, Deref, etc.)
core::option::Option
core::result::Result
core::mem::{size_of, align_of, swap, replace}
core::ptr::{read, write, null, NonNull}
core::slice, core::str
core::sync::atomic // atomic types
core::cell::{Cell, UnsafeCell, RefCell}
core::cmp, core::convert, core::clone, core::default
core::num // numeric conversions
core::panic::PanicInfo // for panic handler要在中使用 crate,需提供全局分配器:
no_stdallocrust
// src/allocator.rs — 使用linked_list_allocator的嵌入式分配器
use linked_list_allocator::LockedHeap;
#[global_allocator]
static ALLOCATOR: LockedHeap = LockedHeap::empty();
pub fn init_heap(heap_start: usize, heap_size: usize) {
unsafe {
ALLOCATOR.lock().init(heap_start as *mut u8, heap_size);
}
}toml
[dependencies]
linked-list-allocator = { version = "0.10", default-features = false }rust
// src/main.rs(裸机环境)
#![no_std]
#![no_main]
extern crate alloc;
use alloc::vec::Vec;
mod allocator;
// 在初始化代码中(BSS/data初始化完成后):
allocator::init_heap(0x20010000, 0x10000); // 在RAM+64KB处分配64KB堆空间
// 现在可以使用分配类型:
let mut v: Vec<u32> = Vec::new();
v.push(42);常见的嵌入式分配器crate:
- : 通用型,支持
linked-list-allocatorno_std - : 基于二次幂的伙伴系统
buddy-alloc - : Doug Lea malloc的移植版本
dlmalloc - : 高性能,适合嵌入式场景
talc
3. Custom global allocator
4. Panic处理器
To use crate in , provide a global allocator:
allocno_stdrust
// src/allocator.rs — embedded allocator using linked_list_allocator
use linked_list_allocator::LockedHeap;
#[global_allocator]
static ALLOCATOR: LockedHeap = LockedHeap::empty();
pub fn init_heap(heap_start: usize, heap_size: usize) {
unsafe {
ALLOCATOR.lock().init(heap_start as *mut u8, heap_size);
}
}toml
[dependencies]
linked-list-allocator = { version = "0.10", default-features = false }rust
// src/main.rs (bare-metal)
#![no_std]
#![no_main]
extern crate alloc;
use alloc::vec::Vec;
mod allocator;
// In init code (after BSS/data init):
allocator::init_heap(0x20010000, 0x10000); // 64KB heap at RAM+64KB
// Now alloc types work:
let mut v: Vec<u32> = Vec::new();
v.push(42);Common embedded allocator crates:
- : general purpose,
linked-list-allocatorno_std - : power-of-two buddy system
buddy-alloc - : port of Doug Lea's malloc
dlmalloc - : fast, suited for embedded
talc
在环境中,必须提供panic处理器——Rust对此有强制要求:
no_stdrust
// 选项1:panic时暂停(最简单,适用于生产环境)
use core::panic::PanicInfo;
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {} // 无限循环
}
// 选项2:通过defmt打印panic信息(带调试探针的嵌入式环境)
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
defmt::error!("{}", defmt::Display2Format(info));
cortex_m::asm::udf(); // 未定义指令 → 硬 fault
}
// 选项3:使用panic crate(在Cargo.toml中添加)
// panic-halt = "0.2" — 自旋循环
// panic-reset = "0.1.1" — 重置MCU
// panic-probe = "0.3" — defmt + probe-rs4. Panic handler
5. 编写可移植的no_std库
In , you must provide a panic handler — Rust requires one:
no_stdrust
// Option 1: halt on panic (simplest, production)
use core::panic::PanicInfo;
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {} // spin forever
}
// Option 2: print panic info via defmt (embedded with debug probe)
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
defmt::error!("{}", defmt::Display2Format(info));
cortex_m::asm::udf(); // undefined instruction → hard fault
}
// Option 3: use a panic crate (in Cargo.toml)
// panic-halt = "0.2" — spin loop
// panic-reset = "0.1.1" — reset MCU
// panic-probe = "0.3" — defmt + probe-rs设计你的库使其支持启用和禁用两种情况:
allocrust
#![no_std]
#[cfg(feature = "alloc")]
extern crate alloc;
pub struct Parser<'a> {
data: &'a [u8], // 借用的切片:无需分配
pos: usize,
}
impl<'a> Parser<'a> {
pub fn new(data: &'a [u8]) -> Self {
Parser { data, pos: 0 }
}
// 核心API:返回借用的数据,无需分配
pub fn next_token(&mut self) -> Option<&'a [u8]> { /* ... */ None }
// 分配API:仅当启用alloc特性时可用
#[cfg(feature = "alloc")]
pub fn collect_all(&mut self) -> alloc::vec::Vec<&'a [u8]> {
let mut tokens = alloc::vec::Vec::new();
while let Some(tok) = self.next_token() {
tokens.push(tok);
}
tokens
}
}5. Writing portable no_std libraries
6. 在主机上测试no_std
Design your library to work with and without :
allocrust
#![no_std]
#[cfg(feature = "alloc")]
extern crate alloc;
pub struct Parser<'a> {
data: &'a [u8], // borrowed slice: no allocation needed
pos: usize,
}
impl<'a> Parser<'a> {
pub fn new(data: &'a [u8]) -> Self {
Parser { data, pos: 0 }
}
// Core API: return borrowed data, no allocation
pub fn next_token(&mut self) -> Option<&'a [u8]> { /* ... */ None }
// Alloc API: only when alloc feature is enabled
#[cfg(feature = "alloc")]
pub fn collect_all(&mut self) -> alloc::vec::Vec<&'a [u8]> {
let mut tokens = alloc::vec::Vec::new();
while let Some(tok) = self.next_token() {
tokens.push(tok);
}
tokens
}
}toml
undefined6. Testing no_std on host
Cargo.toml
toml
undefined[dev-dependencies]
std = [] // 仅在测试中允许使用std(通过cfg控制)
[features]
std = []
```rust
// lib.rs
#![cfg_attr(not(test), no_std)] // 除测试外均为no_std
// 测试代码正常使用std编译 — 仅库代码为no_std或者使用单独的测试工具:
bash
undefinedCargo.toml
在主机上运行测试(测试框架可使用std)
[dev-dependencies]
std = [] # allow std in tests only (via cfg)
[features]
std = []
```rust
// lib.rs
#![cfg_attr(not(test), no_std)] // no_std except during tests
// Tests compile normally with std — only library code is no_stdOr use a separate test harness:
bash
undefinedcargo test --target x86_64-unknown-linux-gnu
Run tests targeting the host (std available for test framework)
使用QEMU针对实际嵌入式目标测试
cargo test --target x86_64-unknown-linux-gnu
cargo test --target thumbv7em-none-eabihf // 失败:裸机环境无测试运行器
Test with the actual embedded target using QEMU
解决方案:使用defmt-test或probe-run进行目标机测试
—
或者:在主机上运行与架构无关的纯逻辑测试
cargo test --target thumbv7em-none-eabihf # fails: no test runner on bare metal
```bashSolution: use defmt-test or probe-run for on-target testing
在无硬件情况下检查no_std兼容性
Or: architecture-neutral pure logic tests on host
—
```bashcargo check --target thumbv7em-none-eabihf
cargo build --target thumbv7em-none-eabihf
undefinedCheck no_std compliance without hardware
相关技能
cargo check --target thumbv7em-none-eabihf
cargo build --target thumbv7em-none-eabihf
undefined- 使用了解probe-rs、defmt以及结合no_std的RTIC
skills/embedded/embedded-rust - 使用进行交叉编译目标配置
skills/rust/rust-cross - 使用了解分配器实现所需的unsafe模式
skills/rust/rust-unsafe - 使用在裸机目标中配置堆区域位置
skills/embedded/linker-scripts
Related skills
—
- Use for probe-rs, defmt, and RTIC with no_std
skills/embedded/embedded-rust - Use for cross-compilation target setup
skills/rust/rust-cross - Use for unsafe patterns needed in allocator implementations
skills/rust/rust-unsafe - Use for heap region placement in bare-metal targets
skills/embedded/linker-scripts
—