格式化输出

本章代码对应分支:fmt-print

概要

通过上一章,我们已经可以在屏幕上打印简单的字符串了,但是我们不应该满足于此。本章我们将实现 rust 中最经典的宏: println! ,用于后续的调试和输出。这需要我们对 rust 的一些特性有一定的了解:

  1. 宏的使用。
  2. trait 的特性。

简单打印字符和字符串

在一个文件内实现过多的功能会使得文件过于冗长,不易阅读与维护,所以我们(在 main.rs 的同级目录下)创建一个新的文件用于管理 io 。现在我们来为 io 实现两个最简单的函数:

  • io.rs
use crate::sbi;

pub fn putchar(ch: char) {
    sbi::console_putchar(ch as u8 as usize);
}

pub fn puts(s: &str) {
    for ch in s.chars() {
        putchar(ch);
    }
}
  • lib.rs
pub mod io;

修改 rust_main 为:

#[no_mangle]
pub fn rust_main() -> ! {
    crate::io::puts("666666");
    loop {}
}

编译运行,屏幕成功输出了 666666

实现 println!

  • io.rs
#[macro_export]
macro_rules! print {
    ($($arg:tt)*) => ({
        $crate::io::_print(format_args!($($arg)*));
    });
}

#[macro_export]
macro_rules! println {
    () => ($crate::print!("\n"));
    ($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*)));
}

#[macro_export] 宏使得外部的库也可以使用这个宏。 format_args! 宏可以将 print(...) 内的部分转换为 fmt::Arguments 类型,用以后续打印。这里我们用到了一个还未实现的函数: _print 。他的实现方法十分神奇,借助了 rust 奇妙的语法。

rust trait 有点类似 C++ 的抽象类,实现 trait 有点类似继承抽象类。这里我们创建了一个空的结构体,但是,由于它实现了 fmt::Write::write_str ,trait 会帮我们自动实现 fmt::Write::write_fmt

如果你想进一步了解这部分内容,可以参考 rust 官方文档 - core::fmt::Writerust 官方教程 - Traits 部分

  • io.rs
use core::fmt::{self, Write};

struct StdOut;

impl fmt::Write for StdOut {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        puts(s);
        Ok(())
    }
}

pub fn _print(args: fmt::Arguments) {
    StdOut.write_fmt(args).unwrap();
}

为了在外部中使用 io.rs 中的宏,我们需要在 pub mod io 的上方添加属性:

#[macro_use]
mod io;

现在我们可以让 println! 进行一些“高难度”的工作,比如打印 panic 信息:

  • lang_items.rs
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
    println!("{}", info);
    loop {}
}
  • init.rs
#[no_mangle]
pub fn rust_main() -> ! {
    let a = "Hello";
    let b = "World";
    println!("{}, {}!", a, b);
    panic!("End of rust_main");
}

再次编译运行,程序输出:

Hello, World!
panicked at 'End of rust_main', src/main.rs:25:5

预告

当 CPU 访问无效的寄存器地址,或进行除零操作,或者进行 系统调用 时,会产生中断。下一章,我们将实现一个简单的中断机制对这些情况进行处理。

results matching ""

    No results matching ""

    results matching ""

      No results matching ""