#[panic_handler]

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

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

下面是一个例子,根据使用开发配置文件(cargo build)或使用发布配置文件(cargo build --release)编译的应用程序具有不同的恐慌行为:

panic-semihostingcrate —— 使用 semihosting 将 panic 信息记录到主机 stderr:

  1. #![no_std]
  2. use core::fmt::{Write, self};
  3. use core::panic::PanicInfo;
  4. struct HStderr {
  5. // ..
  6. # _0: (),
  7. }
  8. #
  9. # impl HStderr {
  10. # fn new() -> HStderr { HStderr { _0: () } }
  11. # }
  12. #
  13. # impl fmt::Write for HStderr {
  14. # fn write_str(&mut self, _: &str) -> fmt::Result { Ok(()) }
  15. # }
  16. #[panic_handler]
  17. fn panic(info: &PanicInfo) -> ! {
  18. let mut host_stderr = HStderr::new();
  19. // 输出日志: "panicked at '$reason', src/main.rs:27:4"
  20. writeln!(host_stderr, "{}", info).ok();
  21. loop {}
  22. }

panic-haltcrate —— panic 时停止线程;消息被丢弃:

  1. #![no_std]
  2. use core::panic::PanicInfo;
  3. #[panic_handler]
  4. fn panic(_info: &PanicInfo) -> ! {
  5. loop {}
  6. }

app crate:

  1. #![no_std]
  2. // dev profile
  3. #[cfg(debug_assertions)]
  4. extern crate panic_semihosting;
  5. // release profile
  6. #[cfg(not(debug_assertions))]
  7. extern crate panic_halt;
  8. fn main() {
  9. // ..
  10. }