没有合适的资源?快使用搜索试试~ 我知道了~
首页探索Rust的非安全一面:高级UnsafeRust编程指南
探索Rust的非安全一面:高级UnsafeRust编程指南
需积分: 0 19 下载量 48 浏览量
更新于2024-06-27
收藏 15.51MB PDF 举报
"《Rust高级编程.pdf》是一本深度探讨Rust语言高级特性和编写非安全(Rust)程序的指南。该书源自官方TheRustonomicon仓库,旨在提供关于编写Unsafe Rust程序所需深入了解的详细内容。不同于基础的《Rust编程语言》,这本书假设读者具备系统编程和基本Rust知识,特别是对于异常安全、指针别名、内存模型、编译器和硬件实现有一定程度的理解。 书中内容涵盖了危险的边界情况,即在unsafe代码中必须面对的复杂问题,如类型安全的边界条件和潜在的性能优化需求。作者强调,在编写程序时,尽管底层实现细节通常被忽视,但在处理非安全代码时,这些细节却至关重要,可能影响程序的正确性和性能。 此外,书中还着重讲解如何在安全(Safe)与不安全(Unsafe)之间找到平衡,尤其是在与其他编程语言交互或需要直接操作底层资源的场景下。虽然本书提供的是"按原样"的知识,没有提供任何形式的保证,但它对于那些有意探索Rust语言深层次特性和非安全编程实践的开发者来说,无疑是一份珍贵的资源。 如果你的目标是长期的Rust编程生涯并且倾向于编写安全代码,那么这本书可能不是你的首选。然而,如果你的项目需要触及Rust的非安全边界,或者你希望理解语言的更深层次,那么《Rust高级编程.pdf》将会为你揭示这个看似坚固实则复杂的语言世界中的微妙之处。因此,这是一本适合有经验的Rust程序员深入学习和挑战自我的书籍。"
资源详情
资源推荐
特殊尺寸类型特殊尺寸类型
原文跟踪 exotic-sizes.md Commit: 7f019ec5c87da39fe0b9b5149e413d914528e945
大多数情况下,我们希望类型具有可静态确定的、非负的大小。 但在Rust中,并非总是如此。
动态大小类型(动态大小类型(DST))
Rust支持动态大小类型(DST):无法静态地确定大小或对齐的类型。 从表面上看,这有点荒谬:Rust必
须知道某些东西的大小和对齐单位才能正确使用它! 在这方面,DST不是正常的类型。 因为它们缺少静态
可知的大小,所以这些类型只能存在于指针背后。 因此,任何指向DST的指针都会变成一个宽指针:由指
针和"使其成为完整类型"的信息组成(下面将详细介绍)。
Rust语言暴露了两个主要的DST:
trait objects: dyn MyTrait
slices: [T] , str , and others
trait对象表示实现了其指定的特质的某种类型。 原始类型通过一个包含了该类型所有信息的vtable被擦
除,以支持运行时反射。 vtable指针让trait对象指针成为了一个完整类型:在运行时,可以从vtable中动态
地获悉指针所指向的对象的大小。
切片只是一些连续内存的一个视图——通常是数组或Vec。 切片指针包含的额外信息只不过是它指向的元
素的数量。 指针所指向对象的运行时大小只是单个元素的大小乘以元素的数量。
Struct 实际上可以直接存储单个DST作为它们的最后一个字段,但这同时也让它们成为了DST:
尽管因为缺少构造手段,这种类型在很大程度上是没用的。 目前,唯一能够构造出自定义DST的方法是,
在类型上增加泛型参数,并加以 ?Sized 修饰:
// Can't be stored on the stack directly
struct MySuperSlice {
info: u32,
data: [u8],
}
(是的,现在,自定义DST是一个很大程度上不够成熟的特性.)
零大小类型(零大小类型(ZST))
Rust还允许声明不占用空间的类型:
就其自身而言,零大小类型(ZST)由于显而易见的原因非常没用。然而,正如Rust中许多奇特的内存布
局决策一样,它们的潜力是发挥在泛型上下文中的:Rust大多数情况下能够理解到,构造或存储ZST的任
何操作都可以简化为no-op。首先,存储ZST甚至是没有意义的——它不占用任何空间。此外,ZST类型的
值只有一个,所以任何需要用到它的时候,都可以凭空构造一个——这也是一种no-op,毕竟它不占用任
何空间。
其中一个最极端的例子是 Set 和 Map 。给定 Map <Key,Value> ,通常 Set <Key> 会被实现为
Map <Key,UselessJunk> 的一层薄薄的封装。在许多语言中,这需要为 UselessJunk 分配空间,并且
需要储存和读取 UselessJunk 后再丢弃它。对编译器来说,证明这种不必要是很困难的。
但是在Rust中,我们可以说 Set <Key> = Map <Key,()> 。现在Rust编译器能够静态地得知每个读取
和存储都是无用的,并且没有分配任何空间。结果就是,通过简单地单态化 HashMap 实现的 HashSet
,在 HashMap 的值上不需要花费任何额外开销。
safe的代码不必担心ZST,但在unsafe的代码中,必须小心ZST类型带来的后果。特别是,对指针偏移是
no-op,并且当申请零大小的内存分配时,标准分配器可以返回 null ,因而无法区分这是否意味着出
struct MySuperSliceable<T: ?Sized> {
info: u32,
data: T
}
fn main() {
let sized: MySuperSliceable<[u8; 8]> = MySuperSliceable {
info: 17,
data: [0; 8],
};
let dynamic: &MySuperSliceable<[u8]> = &sized;
// prints: "17 [0, 0, 0, 0, 0, 0, 0, 0]"
println!("{} {:?}", dynamic.info, &dynamic.data);
}
struct Nothing; // No fields = no size
// All fields have no size = no size
struct LotsOfNothing {
foo: Nothing,
qux: (), // empty tuple has no size
baz: [u8; 0], // empty array has no size
}
现了“内存不足”错误。
空类型空类型
Rust甚至还允许声明无法实例化的类型。 这些类型只能在类型层面进行讨论,而不能在值的层面进行讨
论。 可以通过指定不带变量的枚举来声明一个空类型:
空类型比ZST更加边缘化。 空类型的主要积极示例是类型层面的不可达性。 例如,假设一个API通常需要
返回一个结果,但实际上,这个API在特定情况是绝对可靠的。 这一点,通过返回一个 Result
<T,Void> ,就可以在类型层面表达出来。 API的使用者可以自信地对这样的结果进行拆箱,因为已经知
道这个值在静态上不可能是 Err ——否则就意味着需要提供一个 Void 类型的值,这是不可能的。
原则上,Rust可以基于这个事实做一些有趣的分析和优化。 例如, Result <T,Void> 仅表示为 T ,
因为 Err 情况实际上并不存在(严格来说,这只是一个无法保证的优化,因此,例如将一个 Result
<T,Void> 转换为另一个 Result <T,Void> 仍然是未定义行为)。
以下代码也可以通过编译:
但是这个trick现在还不能用。
关于空类型的最后一个细微的细节是,构造一个空类型的裸指针是合法的,但是解引用它们是未定义的行
为,因为这没有意义。
我们建议不要使用 * const Void 对C的 void * 类型进行模拟。 很多人一开始会这样做,但很快就
遇到了麻烦,因为Rust没有任何的安全措施来防止尝试用不安全的代码去实例化空类型,如果你这样做,
那就是未定义行为。 这尤其成问题,因为开发人员习惯将原始指针转换为引用,而 &Void 也是未定义
行为。
* const() (或等效的)适用于 void * ,并且可以在没有任何安全问题的情况下成为引用。 它仍
然不会阻止您尝试读取或写入值,但至少它会编译为 no-op 而不是UB。
外部类型外部类型
有一个已经被接受的 RFC 为未知大小的类型增加了一种合适的类型,称为 extern 类型,这将使Rust
开发人员更准确地模拟C的 void * 和其他"声明了但未定义"类型的内容。 但是,从Rust 2018开始,这
个特性在 size_of :: <MyExternType>() 应该如何表现上陷入了困境。
enum Void {} // No variants = EMPTY
enum Void {}
let res: Result<u32, Void> = Ok(0);
// Err doesn't exist anymore, so Ok is actually irrefutable.
let Ok(num) = res;
替代数据布局替代数据布局
源- other-reprs Commit: 7f019ec5c87da39fe0b9b5149e413d914528e945
Rust允许您使用特定的内存布局策略以替代默认的策略。 这里有 reference .
repr(C)
这是最重要的一种 repr 。它的目的很简单,就是和C保持一致。数据的顺序、大小、对齐方式都和你
在C或C++中见到的一模一样。所有你需要通过FFI交互的类型都应该指定 repr(C) ,因为C是程序设计
领域的世界语。而且如果我们要在数据布局方面玩一些花样的话,比如把数据重新解析成另一种类型,
repr(C) 也是很有必要的。
我们强烈建议您使用 rust-bindgen 和/或[cbdingen]来管理您的FFI边界。 Rust团队与这些项目密切合
作,以确保它们运行稳健,并与当前和未来有关类型布局和 reprs 保证兼容。
必须牢记 repr(C) 与Rust更具特殊的数据布局特性的相互作用。 由于其"用于FFI"和"用于布局控制"的
双重目的, repr(C) 可以应用于通过FFI边界时无意义或有问题的类型。
ZST的大小是0,尽管这在C语言中不是标准行为,而且它也与C++中的空类型有着明显的不同,C++的
空类型还是要占用一个字节的空间的。
DST的指针(胖指针),元组都是C中没有的,因此也不是FFI安全的。
携带变量的Enum成员这种概念也时C/C++中所没有的,但有一个定义好的合法的bridge类型 really-
tagged 。
如果 T 是 FFI安全的不可空指针 的,就能保证 Option<T> 和 T 有着同样的内存布局和ABI,因此
Option<T> 也是FFI安全的。如前言所写, T 如果被转换为 & 、 &mut 或者函数指针,也永远都
不会是空指针。
Tuple结构体会像普通结构体一样对待 repr(C) ,与普通结构体的唯一的区别就是Tuple结构体的成员
是匿名的。
Fieldless的Enum, repr(C) 等价于 repr(u*) (见下一部分)之一。目标平台上的C语言的ABI决
定了会使用等价于C的Enum的默认大小作为Rust侧Enum的大小。要注意,在C语言中,Enum的内存布
局是由实现定义(Implementation defined)的,所以这确实需要全力猜测(笑。特别地,C代码的某些
编译选项也会影响到猜测结果。
repr(C) is equivalent to one of repr(u*) (see the next section) for fieldless enums. The chosen size
is the default enum size for the target platform's C application binary interface (ABI). Note that enum
representation in C is implementation defined, so this is really a "best guess". In particular, this may be
incorrect when the C code of interest is compiled with certain flags.
Fieldless enums with repr(C) or repr(u*) still may not be set to an integer value without a
corresponding variant, even though this is permitted behavior in C or C++. It is undefined behavior to
剩余150页未读,继续阅读
2201_75312950
- 粉丝: 0
- 资源: 2
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- JDK 17 Linux版本压缩包解压与安装指南
- C++/Qt飞行模拟器教员控制台系统源码发布
- TensorFlow深度学习实践:CNN在MNIST数据集上的应用
- 鸿蒙驱动HCIA资料整理-培训教材与开发者指南
- 凯撒Java版SaaS OA协同办公软件v2.0特性解析
- AutoCAD二次开发中文指南下载 - C#编程深入解析
- C语言冒泡排序算法实现详解
- Pointofix截屏:轻松实现高效截图体验
- Matlab实现SVM数据分类与预测教程
- 基于JSP+SQL的网站流量统计管理系统设计与实现
- C语言实现删除字符中重复项的方法与技巧
- e-sqlcipher.dll动态链接库的作用与应用
- 浙江工业大学自考网站开发与继续教育官网模板设计
- STM32 103C8T6 OLED 显示程序实现指南
- 高效压缩技术:删除重复字符压缩包
- JSP+SQL智能交通管理系统:违章处理与交通效率提升
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功