#[panic_handler]

#[panic_handler] 用于定义在 #![no_std] 应用程序中 panic! 的行为。#[panic_handler] 属性必须应用于签名 fn(&PanicInfo) -> ! 的函数,并且这样的函数必须在二进制文件/动态链接库/C动态库 crate 的依赖关系图中出现一次PanicInfo 的 API 可以在API 文档中找到。

鉴于 #![no_std] 应用程序没有标准输出,并且一些 #![no_std] 应用程序,例如嵌入式应用程序,在开发和发布时需要不同的 panic 行为,拥有 panic crate 会很有帮助,panic crate 仅包含 #[panic_handler]。这样,应用程序可以通过简单地链接到不同的 panic crate 来轻松切换 panic 行为。

下面展示了一个示例,其中应用程序根据是使用 dev 配置文件(cargo build)还是使用 release 配置文件(cargo build --release)编译而具有不同的 panic 行为。

panic-semihosting crate -- 使用半主机将 panic 消息记录到主机 stderr

#![no_std]

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

struct HStderr {
    // ..
    _0: (),
}

impl HStderr {
    fn new() -> HStderr { HStderr { _0: () } }
}

impl fmt::Write for HStderr {
    fn write_str(&mut self, _: &str) -> fmt::Result { Ok(()) }
}

#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
    let mut host_stderr = HStderr::new();

    // logs "panicked at '$reason', src/main.rs:27:4" to the host stderr
    writeln!(host_stderr, "{}", info).ok();

    loop {}
}

panic-halt crate -- 在 panic 时停止线程;消息被丢弃

#![no_std]

use core::panic::PanicInfo;

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

app crate

#![no_std]

// dev profile
#[cfg(debug_assertions)]
extern crate panic_semihosting;

// release profile
#[cfg(not(debug_assertions))]
extern crate panic_halt;

fn main() {
    // ..
}