gpt4 book ai didi

rust - 如何使用 no_std 且没有分配器将输出格式化为字节数组?

转载 作者:行者123 更新时间:2023-11-29 08:01:14 25 4
gpt4 key购买 nike

我想做这样的事情:

let x = 123;
let mut buf = [0 as u8; 20];
format_to!(x --> buf);
assert_eq!(&buf[..3], &b"123"[..]);

使用 #![no_std] 并且没有任何内存分配器。

据我了解,u64 有一个 core::fmt::Display 的实现,如果可能我想使用它。

换句话说,我想做类似format!(...) 的事情,但没有内存分配器。我该怎么做?

最佳答案

让我们从标准版本开始:

use std::io::Write;

fn main() {
let x = 123;
let mut buf = [0 as u8; 20];
write!(&mut buf[..], "{}", x).expect("Can't write");
assert_eq!(&buf[0..3], b"123");
}

如果我们然后删除标准库:

#![feature(lang_items)]
#![no_std]

use core::panic::PanicInfo;

#[lang = "eh_personality"]
extern "C" fn eh_personality() {}

#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
loop {}
}

fn main() {
let x = 123;
let mut buf = [0 as u8; 20];
write!(&mut buf[..], "{}", x).expect("Can't write");
assert_eq!(&buf[0..3], b"123");
}

我们得到错误

error[E0599]: no method named `write_fmt` found for type `&mut [u8]` in the current scope
--> src/main.rs:17:5
|
17 | write!(&mut buf[..], "{}", x).expect("Can't write");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

write_fmtcore::fmt::Write 在核心库中实现.如果我们自己实现它,我们能够传递该错误:

#![feature(lang_items)]
#![feature(start)]
#![no_std]

use core::panic::PanicInfo;

#[lang = "eh_personality"]
extern "C" fn eh_personality() {}

#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
loop {}
}

use core::fmt::{self, Write};

struct Wrapper<'a> {
buf: &'a mut [u8],
offset: usize,
}

impl<'a> Wrapper<'a> {
fn new(buf: &'a mut [u8]) -> Self {
Wrapper {
buf: buf,
offset: 0,
}
}
}

impl<'a> fmt::Write for Wrapper<'a> {
fn write_str(&mut self, s: &str) -> fmt::Result {
let bytes = s.as_bytes();

// Skip over already-copied data
let remainder = &mut self.buf[self.offset..];
// Check if there is space remaining (return error instead of panicking)
if remainder.len() < bytes.len() { return Err(core::fmt::Error); }
// Make the two slices the same length
let remainder = &mut remainder[..bytes.len()];
// Copy
remainder.copy_from_slice(bytes);

// Update offset to avoid overwriting
self.offset += bytes.len();

Ok(())
}
}

#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
let x = 123;
let mut buf = [0 as u8; 20];
write!(Wrapper::new(&mut buf), "{}", x).expect("Can't write");
assert_eq!(&buf[0..3], b"123");
0
}

请注意,我们正在复制 io::Cursor 的行为进入这个包装。通常,多次写入 &mut [u8] 会相互覆盖。这有利于重用分配,但当您连续写入相同数据时就没用了。

如果你愿意,那就只需要编写一个宏。

您还应该能够使用像 arrayvec 这样的 crate ,它已经为您编写了这段代码。这是未经测试的:

#![feature(lang_items)]
#![feature(start)]
#![no_std]

use core::panic::PanicInfo;

#[lang = "eh_personality"]
extern "C" fn eh_personality() {}

#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}

use arrayvec::ArrayString; // 0.4.10
use core::fmt::Write;

#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
let x = 123;
let mut buf = ArrayString::<[u8; 20]>::new();
write!(&mut buf, "{}", x).expect("Can't write");
assert_eq!(&buf, "123");
0
}

关于rust - 如何使用 no_std 且没有分配器将输出格式化为字节数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55151575/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com