30|Unsafe Rust:如何用C++的方式打开Rust?
陈天
该思维导图由 AI 生成,仅供参考
你好,我是陈天。
到目前为止,我们撰写的代码都在 Rust 精心构造的内存安全的国度里做一个守法好公民。通过遵循所有权、借用检查、生命周期等规则,我们自己的代码一旦编译通过,就相当于信心满满地向全世界宣布:这个代码是安全的!
然而,安全的 Rust 并不能适应所有的使用场景。
首先,为了内存安全,Rust 所做的这些规则往往是普适性的,编译器会把一切可疑的行为都严格地制止掉。可是,这种一丝不苟的铁面无情往往会过于严苛,导致错杀。
就好比“屋子的主人只会使用钥匙开门,如果一个人尝试着撬门,那一定是坏人”,正常情况下,这个逻辑是成立的,所有尝试撬门的小偷,都会被抓获(编译错误);然而,有时候主人丢了钥匙,不得不请开锁匠开门(unsafe code),此时,是正常的诉求,是可以网开一面的。
其次,无论 Rust 将其内部的世界构建得多么纯粹和完美,它总归是要跟不纯粹也不完美的外界打交道,无论是硬件还是软件。
计算机硬件本身是 unsafe 的,比如操作 IO 访问外设,或者使用汇编指令进行特殊操作(操作 GPU 或者使用 SSE 指令集)。这样的操作,编译器是无法保证内存安全的,所以我们需要 unsafe 来告诉编译器要法外开恩。
同样的,当 Rust 要访问其它语言比如 C/C++ 的库,因为它们并不满足 Rust 的安全性要求,这种跨语言的 FFI(Foreign Function Interface),也是 unsafe 的。
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
- 深入了解
- 翻译
- 解释
- 总结
Rust语言中的unsafe代码是为了在需要时打开Rust的内存安全限制,主要用于处理硬件交互、跨语言调用和性能优化等情况。本文深入介绍了unsafe Rust的使用场景和注意事项,包括实现unsafe trait、调用已有的unsafe接口、对裸指针做解引用以及使用FFI。特别强调了实现Send/Sync trait时需要小心谨慎,避免出现程序崩溃的情况。文章还提到了不推荐的使用unsafe的场景,包括处理未初始化数据、访问可变静态变量、以及使用unsafe提升性能。此外,还介绍了如何撰写和调用unsafe代码时需要注意的安全性要求。总的来说,本文对于想要深入了解Rust语言内存安全特性的读者具有一定的参考价值。
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《陈天 · Rust 编程第一课》,新⼈⾸单¥68
《陈天 · Rust 编程第一课》,新⼈⾸单¥68
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(8)
- 最新
- 精选
- 罗杰先把safe rust 弄清楚,再考虑 unsafe 的事
作者回复: 对!
2021-11-051 - TheLudlowspub fn as_mut_ptr(&mut self) -> *mut u8 { self as *mut str as *mut u8 } 请问老师这个转换为什么要多一层 *mut str ,as *mut str 和 as *mut u8的区别是什么,还有说这个as 转换的过程做了什么
作者回复: as 不会做什么,只是把一种类型当成另一种类型处理。第一个转换是把 &str 引用转换成对应的裸指针,第二个是把裸指针从一种类型转换成另一种类型。
2021-11-16 - D. D不能直接使用 get_unchecked_mut() 去实现,因为即使在 unsafe 代码里面也不能对一个变量同时进行多个可变借用,需要先转换成裸指针。 不知道这样实现可以吗? fn split_mut(s: &mut str, sep: char) -> Option<(&mut str, &mut str)> { let pos = s.find(sep); pos.map(|pos| { let len = s.len(); let sep_len = sep.len_utf8(); let ptr1: *mut u8 = s.as_mut_ptr(); let ptr2: *mut u8 = s[(pos + sep_len)..].as_mut_ptr(); unsafe { let s1 = std::slice::from_raw_parts_mut(ptr1, pos); let s2 = std::slice::from_raw_parts_mut(ptr2, len - (pos + sep_len)); (std::str::from_utf8_unchecked_mut(s1), std::str::from_utf8_unchecked_mut(s2)) } }) } https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=98493d711d7a002c318aace31ecb2af0
作者回复: 嗯,是这个思路。用 ptr.add() 来处理指针会更好。参考代码见:https://github.com/tyrchen/geektime-rust/blob/master/30_unsafe/examples/split.rs#L26
2021-11-06 - 终生恻隐fn split_mut(s: &mut str, sep: char) -> Option<(&mut str, &mut str)> { let pos = s.find(sep); pos.map(|pos| unsafe { let len = s.len(); let sep_len = sep.len_utf8(); let ss = s.as_mut_ptr(); let mut scl = &mut *(slice_from_raw_parts_mut(ss, pos)); let mut scr = &mut *( slice_from_raw_parts_mut( ss.offset((pos + sep_len) as isize), len-(pos + sep_len) ) ); // println!("left {}", from_utf8_unchecked_mut(scl)); // println!("left {}", from_utf8_unchecked_mut(scr)); (from_utf8_unchecked_mut(scl), from_utf8_unchecked_mut(scr)) }) }
作者回复: 嗯,思路是对的。参考代码:https://github.com/tyrchen/geektime-rust/blob/master/30_unsafe/examples/split.rs#L26
2021-11-05 - pedro因为 Send / Sync 是 auto trait,所以大部分情况下,你自己的数据结构不需要实现 Send / Sync,然而,当你在数据结构里使用裸指针时,因为裸指针是没有实现 Send/Sync 的,连带着你的数据结构也就没有实现 Send/Sync。但很可能你的结构是线程安全的,你也需要它线程安全。 但很可能你的结构是线程安全的,你也需要它线程安全? 这句话我咋理解不了啊,是线程安全的,咋还需要它线程安全?
作者回复: 你如果可以保证它线程安全的话,需要实现 Send/Sync 告诉编译器它线程安全。否则编译器会报错。
2021-11-055 - 杨学者let arr: [usize; 6] = unsafe { std::mem::transmute(map) }; 新版的rust1.72stable报错了,因为hashmap的源码更新了2023-09-02归属地:上海
- 约书亚fn split_mut(s: &mut str, sep: char) -> Option<(&mut str, &mut str)> { let pos = s.find(sep); pos.map(|pos| { let len = s.len(); let sep_len = sep.len_utf8(); let p = s.as_mut_ptr(); unsafe { let s1 = from_raw_parts_mut(p, pos); let s2 = from_raw_parts_mut(p.add(pos + sep_len), len - pos - sep_len); (from_utf8_unchecked_mut(s1), from_utf8_unchecked_mut(s2)) } }) }2022-10-04归属地:德国
- 进击的Lancelot关于思考题,我的实现: ```rust fn split_mut(s: &mut str, sep: char) -> Option<(&mut str, &mut str)> { let pos = s.find(sep); pos.map(|pos| { let len = s.len(); let sep_len = sep.len_utf8(); let s1 = s.get_mut(0..pos).unwrap().as_mut_ptr(); let s2 = s.get_mut(pos + sep_len..len).unwrap().as_mut_ptr(); unsafe { let s1 = from_raw_parts_mut(s1, pos); let s2 = from_raw_parts_mut(s2, len - pos - sep_len); (from_utf8_unchecked_mut(s1), from_utf8_unchecked_mut(s2)) } }) } ``` playground 连接: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=7be8e52e1278665816a03eb30fbfaf602022-09-17归属地:广东
收起评论