🐼
Rustのno_std環境でStringを使う
経緯
STM32マイコンでRustを勉強をしててUART出力できるようになった際に、no_std環境で可変文字列(String)を扱いたくなって調査したので備忘録
確認環境
| バージョン | |
|---|---|
| rustc | rustc 1.62.0-nightly (8bf93e9b6 2022-04-09) |
方法
allocの実装が必要。
そのために以下手順を実施
| No | 実施内容 |
|---|---|
| 1 | Nightly Rustへの切り替え |
| 2 | #[global_allocator]アトリビュート指定オブジェクトの宣言 |
| 3 | #[alloc_error_handler]アトリビュート指定の関数実装 |
| 4 | Stringのuse宣言追加 |
Nightly Rustへの切り替え
必須ではないが手順2、手順3のために基本的に必要。ないとビルドエラーになる。
ターミナルで以下実施
rustup override set nightly
global_allocatorアトリビュート指定オブジェクトの宣言
アプリのどこかに#[lobal_allocator]アトリビュートを指定したグローバル変数を宣言する必要がある。
この変数の型はGlobalAllocトレイトを実装している必要がある。
自前で実装してもよいが、ここでは公開されているalloc-cortex-mを使用。
alloc-cortex-m使用例
3手順に分けて記載
- Cargo.tomlのdependenciesに追加
Cargo.toml
[dependencies]
alloc-cortex-m = "0.4.2"
- アプリ内にグローバル変数宣言
use alloc_cortex_m::CortexMHeap;
#[global_allocator]
static ALLOCATOR: CortexMHeap = CortexMHeap::empty();
- アプリ開始時に初期化
#[entry]
fn main() -> ! {
{
use core::mem::MaybeUninit;
const HEAP_SIZE: usize = 1024*20; //20KBの領域
static mut HEAP: [MaybeUninit<u8>; HEAP_SIZE] =
[MaybeUninit::uninit(); HEAP_SIZE];
unsafe { ALLOCATOR.init(HEAP.as_ptr() as usize, HEAP_SIZE) }
}
alloc_error_handlerアトリビュート指定の関数実装
以下2つ必要
-
#![feature(alloc_error_handler)]をルートモジュール先頭に追加
ルートモジュール先頭でないとビルドエラーになる
main.rs
#![no_std]
#![no_main]
#![feature(alloc_error_handler)]
- 関数実装
アプリ内に関数を実装する
use core::alloc::Layout;
#[alloc_error_handler]
fn oom(_: Layout) -> ! {
loop {}
}
Stringのuse宣言追加
アプリでStringを使用するためにuseが必要。
他にもto_string()関数やformat()マクロなどを使う際にも都度必要。
おそらく一纏めにするor記載省略する方法があるが、ここでは明示的に記載。
use alloc::string::String;
use alloc::string::ToString;
use alloc::format;
fn test() {
let base_string = String::from("aiueo:"); //Stringのuse必要
let mut count:u32 = 0;
loop {
let custom_string = format!("{}{}{}", //formatのuse必要
base_string, count.to_string(),"\n"); //ToStringのuse必要
//custom_stringを使ったUART送信処理
...
count=count+1;
}
}
備考
Nightly Rustを使わない方法
手順2、手順3に対して以下実施によりStable Rustでもalloc実装可能
- 手順2(
global_allocatorアトリビュート指定オブジェクトの宣言)に対して
Nightly Rustを要求しないアロケータを使用する (alloc-cortex-mはNG)
または自前でGlobalAllocトレイトを実装する。
自前で実装する場合は参考1.を参照
- 手順3(
alloc_error_handlerアトリビュート指定の関数実装)に対して
nightly-crimesを使用してalloc_error_handler関係を囲む。
Cargo.toml
[dependencies]
nightly-crimes = "1.0.2"
main.rs
#![no_std]
#![no_main]
use nightly_crimes::nightly_crimes;
nightly_crimes! {
#![feature(alloc_error_handler)]
use core::alloc::Layout;
#[alloc_error_handler]
fn oom(_: Layout) -> ! {
loop {}
}
}
参考
Discussion