解引用裸指针的步骤?
解读
在国内 Rust 岗位面试中,“裸指针”(const T / mut T)属于 unsafe 块** 必考点。面试官想确认两点:
- 你是否清楚裸指针与引用的本质区别(无生命周期、无借用检查、可空、可悬垂);
- 你是否掌握**“三步走”安全仪式**:校验非空 → 对齐检查 → 用 unsafe 块解引用,并能在答题时主动提及 std::ptr::read/write/offset 等标准函数。
答得太简略(只写*ptr)会被追问“万一空指针怎么办”;答得太深(直接聊 MMU 页表)又容易“过度设计”。因此,给出**“编译期 + 运行期”双保险步骤**最合国内面试官口味。
知识点
- 裸指针类型:*const T / *mut T,不实现 Send/Sync,默认不保证对齐与初始化。
- 解引用唯一入口:必须放在 unsafe {} 块内,编译器放弃检查,程序员自负其责。
- 空指针校验:使用 is_null() 方法,与 C 的
ptr == NULL对应。 - 对齐检查:利用
ptr as usize % mem::align_of::<T>() == 0,防止未对齐 UB。 - 标准库辅助:
- std::ptr::read(ptr) / write(ptr, val) —— 避免移动语义异常;
- offset / wrapping_offset / add —— 指针算术,需保证 in-bounds;
- NonNull<T> —— 封装非空保证,可与 Box::into_raw 配对使用。
- 内存模型:Rust 采用 LLVM dereferenceable 属性,若指针无效即触发 UB,国内大厂代码审计会直接打回。
- 常见坑:
- 解引用后临时引用不得越过 unsafe 块边界,否则产生 unbound lifetime;
- 多线程场景需自行加 AtomicPtr 或 Mutex,裸指针本身不提供同步。
答案
步骤如下,缺一不可:
- 空指针校验:
if ptr.is_null() { return Err("null"); } - 对齐校验:
assert!((ptr as usize) % mem::align_of::<T>() == 0); - unsafe 块内解引用:
unsafe { // 若只读 let val = *ptr; // 若写 *ptr = new_val; // 或利用 std::ptr::read/write 避免 Drop 冲突 } - (可选但加分)生命周期收敛:把得到的引用
&*ptr或&mut *ptr用 std::mem::replace 或 ManuallyDrop 包裹,防止越过 unsafe 块泄漏生命周期。
一句话总结:“先判空,再对齐,最后 unsafe 解引用;任何一步省掉,UB 等着你。”
拓展思考
- 与 C/C++ 交互:
通过 extern "C" FFI 拿到 *const c_char 后,先用 CStr::from_ptr 做非空 + 0 结尾双重校验,再转 &str,可展示你对跨语言内存安全的成熟认知。 - 零拷贝网络框架:
国内云原生面试常问 tokio + mmap,把裸指针映射到 &[u8] 切片时,需用 slice::from_raw_parts 并保证 *length mem::size_of::<T>() 不越页,否则内核发 SIGBUS。 - ** Miri 与 KASAN**:
回答完“三步走”后,可主动补充“CI 阶段跑 Miri 检测 UB”,或“Linux 内核模块用 KASAN + Rust 裸指针”,让面试官感受到你对国内大厂质量门禁的贴合。