rust-no-std

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Rust no_std

Rust no_std

Purpose

用途

Guide agents through
#![no_std]
Rust development: what
core
and
alloc
provide vs
std
, implementing custom global allocators, panic handler selection for embedded targets, and strategies for testing
no_std
crates on the host machine.
引导开发者完成
#![no_std]
Rust开发:讲解
core
alloc
std
的区别,实现自定义全局分配器,为嵌入式目标选择panic处理器,以及在主机环境测试
no_std
crate的策略。

Triggers

触发场景

  • "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?"
  • "如何编写
    #![no_std]
    Rust crate?"
  • "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
undefined
rust
// 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
undefined

Cargo.toml

Cargo.toml

[features] default = [] alloc = [] # opt-in to heap allocation
[dependencies]
[features] default = [] alloc = [] // 可选启用堆分配
[dependencies] // 仅使用兼容no_std的依赖
undefined

no_std-compatible dependencies only

2. core vs alloc vs std

undefined
Crate需要操作系统需要堆提供功能
core
基础类型、trait、迭代器、格式化、内存操作、指针、切片、Option、Result
alloc
是(需分配器)Vec、String、Box、Arc、Rc、HashMap(需要全局分配器)
std
包含core和alloc的所有内容 + 操作系统API(线程、文件、套接字、环境变量)
std
会重导出
core
alloc
中的所有内容,因此当
std
可用时,
use std::fmt
use core::fmt
效果等价。
core
可用的功能(无需堆、无需操作系统):
rust
// 这些在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. 自定义全局分配器

CrateRequires OSRequires heapProvides
core
NoNoPrimitives, traits, iter, fmt, mem, ptr, slice, option, result
alloc
NoYes (allocator)Vec, String, Box, Arc, Rc, HashMap (requires global allocator)
std
YesYesAll of core + alloc + OS APIs (threads, files, sockets, env)
std
re-exports everything in
core
and
alloc
, so
use std::fmt
and
use core::fmt
are equivalent when
std
is available.
What's available in
core
only (no heap, no OS):
rust
// 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
要在
no_std
中使用
alloc
crate,需提供全局分配器:
rust
// 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-allocator
    : 通用型,支持
    no_std
  • buddy-alloc
    : 基于二次幂的伙伴系统
  • dlmalloc
    : Doug Lea malloc的移植版本
  • talc
    : 高性能,适合嵌入式场景

3. Custom global allocator

4. Panic处理器

To use
alloc
crate in
no_std
, provide a global allocator:
rust
// 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:
  • linked-list-allocator
    : general purpose,
    no_std
  • buddy-alloc
    : power-of-two buddy system
  • dlmalloc
    : port of Doug Lea's malloc
  • talc
    : fast, suited for embedded
no_std
环境中,必须提供panic处理器——Rust对此有强制要求:
rust
// 选项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-rs

4. Panic handler

5. 编写可移植的no_std库

In
no_std
, you must provide a panic handler — Rust requires one:
rust
// 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
设计你的库使其支持启用和禁用
alloc
两种情况:
rust
#![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
alloc
:
rust
#![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
undefined

6. 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
undefined

Cargo.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_std
Or use a separate test harness:
bash
undefined
cargo 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

```bash

Solution: use defmt-test or probe-run for on-target testing

在无硬件情况下检查no_std兼容性

Or: architecture-neutral pure logic tests on host


```bash
cargo check --target thumbv7em-none-eabihf cargo build --target thumbv7em-none-eabihf
undefined

Check no_std compliance without hardware

相关技能

cargo check --target thumbv7em-none-eabihf cargo build --target thumbv7em-none-eabihf
undefined
  • 使用
    skills/embedded/embedded-rust
    了解probe-rs、defmt以及结合no_std的RTIC
  • 使用
    skills/rust/rust-cross
    进行交叉编译目标配置
  • 使用
    skills/rust/rust-unsafe
    了解分配器实现所需的unsafe模式
  • 使用
    skills/embedded/linker-scripts
    在裸机目标中配置堆区域位置

Related skills

  • Use
    skills/embedded/embedded-rust
    for probe-rs, defmt, and RTIC with no_std
  • Use
    skills/rust/rust-cross
    for cross-compilation target setup
  • Use
    skills/rust/rust-unsafe
    for unsafe patterns needed in allocator implementations
  • Use
    skills/embedded/linker-scripts
    for heap region placement in bare-metal targets