Rust 中的数据布局-repr
repr(Rust)
首先,所有类型都有一个以字节为单位的对齐方式,一个类型的对齐方式指定了哪些地址可以用来存储该值。一个具有对齐方式n
的值只能存储在n
的倍数的地址上。所以对齐方式 2 意味着你必须存储在一个偶数地址,而 1 意味着你可以存储在任何地方。对齐至少是 1,而且总是 2 的幂。
基础类型通常按照其大小对齐,尽管这是特定平台的行为。例如,在 x86 上u64
和f64
通常被对齐到 4 字节(32 位)。
一个类型的大小必须始终是其对齐方式的倍数(零是任何对齐方式的有效大小),这就保证了该类型的数组总是可以通过偏移其大小的倍数来进行索引。注意,在动态大小的类型的情况下,一个类型的大小和对齐方式可能不是静态的。
Rust 给你提供了以下方式来布置复合数据。
- structs (命名复合类型 named product types)
- tuples (匿名复合类型 anonymous product types)
- arrays (同质复合类型 homogeneous product types)
- enums (命名总和类型 —— 有标签的联合体 named sum types -- tagged unions)
- unions (无标签的联合体 untagged unions)
如果一个枚举的变体都没有相关联的数据,那么它就被称为无域。
默认情况下,复合结构的对齐方式等于其字段对齐方式的最大值。因此,Rust 会在必要时插入填充,以确保所有字段都正确对齐,并且整个类型的大小是其对齐的倍数。比如说:
struct A {
a: u8,
b: u32,
c: u16,
}
将在目标上以 32 位对齐,将这些基本类型对齐到它们各自的大小。因此,整个结构的大小将是 32 位的倍数。它可能变成:
struct A {
a: u8,
_pad1: [u8; 3], // 需要和 `b` 内存对齐
b: u32,
c: u16,
_pad2: [u8; 2], // 让总体的大小是 4 的倍数
}
或者,也许:
struct A {
b: u32,
c: u16,
a: u8,
_pad: u8,
}
所有数据都存储在结构中,正如你在 C 语言中所期望的那样。然而,除了数组(密集包装且无序)之外,数据的布局在默认情况下没有指定。给出以下两个结构的定义:
struct A {
a: i32,
b: u64,
}
struct B {
a: i32,
b: u64,
}
Rust 确实保证 A 的两个实例的数据布局完全相同。然而,Rust 目前并不保证 A 的实例与 B 的实例具有相同的字段排序或填充。
对于我们编写的 A 和 B 来说,这一点似乎是迂腐的,但是 Rust 的其他几个特性使得该语言有必要以复杂的方式来处理数据布局。
例如,考虑这个结构:
struct Foo<T, U> {
count: u16,
data1: T,
data2: U,
}
现在考虑一下Foo<u32, u16>
和Foo<u16, u32>
的单态。如果 Rust 按照指定的顺序排列字段,我们希望它能对结构中的值进行填充以满足其对齐要求。因此,如果 Rust 不对字段重新排序,我们希望它能产生以下结果:
struct Foo<u16, u32> {
count: u16,
data1: u16,
data2: u32,
}
struct Foo<u32, u16> {
count: u16,
_pad1: u16,
data1: u32,
data2: u16,
_pad2: u16,
}
后一种情况很显然浪费了空间,对空间的最佳利用要求不同的单体有不同的字段排序。
枚举使这种考虑变得更加复杂,直观地说,一个枚举如下:
enum Foo {
A(u32),
B(u64),
C(u8),
}
可能会被布局成:
struct FooRepr {
data: u64, // 根据 tag 的不同,这一项可以为 u64,u32,或者 u8
tag: u8, // 0 = A,1 = B, 2 = C
}
事实上,这大约正是它的布局方式(根据tag
的大小和位置来调整)。
然而,在一些情况下,这样的表述是低效的。这方面的典型案例是 Rust 的“空指针优化”:一个由单个外部单元变量(例如None
)和一个(可能嵌套的)非空指针变量(例如Some(&T)
)组成的枚举,使得标签没有必要。空指针可以安全地被解释为单位(None
)的变体。这导致的结果是,例如,size_of::<Option<&T>>() == size_of::<&T>()
。
在 Rust 中,有许多类型会包含不可为空的指针,如Box<T>
、Vec<T>
、String
、&T
和&mut T
。同样地,我们可以想象嵌套的枚举将它们的标记集中到一个单一的字段中,因为根据定义,它们的有效值范围有限。原则上,枚举可以使用相当复杂的算法,在整个嵌套类型中用禁止使用的值来存储枚举类型。因此,我们今天不指定枚举布局是特别符合预期的。
Rust 中的数据布局-repr的更多相关文章
- Rust 中的数据布局--可选的数据布局
Rust 允许你指定不同于默认的数据布局策略,并为你提供了不安全代码指南. repr(C) 这是最重要的"repr".它的意图相当简单:做 C 所做的事.字段的顺序.大小和对齐方式 ...
- Rust 中的数据布局--非正常大小的类型
非正常大小的类型 大多数的时候,我们期望类型在编译时能够有一个静态已知的非零大小,但这并不总是 Rust 的常态. Dynamically Sized Types (DSTs) Rust 支持动态大小 ...
- 借助 SIMD 数据布局模板和数据预处理提高 SIMD 在动画中的使用效率
原文链接 简介 为发挥 SIMD1 的最大作用,除了对其进行矢量化处理2外,我们还需作出其他努力.可以尝试为循环添加 #pragma omp simd3,查看编译器是否成功进行矢量化,如果性能有所提升 ...
- 【译】对Rust中的std::io::Error的研究
原文标题:Study of std::io::Error 原文链接:https://matklad.github.io/2020/10/15/study-of-std-io-error.html 公众 ...
- 如何在ASP.NET Web站点中统一页面布局[Creating a Consistent Layout in ASP.NET Web Pages(Razor) Sites]
如何在ASP.NET Web站点中统一页面布局[Creating a Consistent Layout in ASP.NET Web Pages(Razor) Sites] 一.布局页面介绍[Abo ...
- 在 ASP.NET 中创建数据访问和业务逻辑层(转)
.NET Framework 4 当在 ASP.NET 中处理数据时,可从使用通用软件模式中受益.其中一种模式是将数据访问代码与控制数据访问或提供其他业务规则的业务逻辑代码分开.在此模式中,这两个层均 ...
- WPF中的数据验证
数据验证 WPF的Binding使得数据能够在数据源和目标之间流通,在数据流通的中间,便能够对数据做一些处理. 数据转换和数据验证便是在数据从源到目标 or 从目标到源 的时候对数据的验证和转换. V ...
- c++继承中的内存布局
今天在网上看到了一篇写得非常好的文章,是有关c++类继承内存布局的.看了之后获益良多,现在转在我自己的博客里面,作为以后复习之用. ——谈VC++对象模型(美)简.格雷程化 译 译者前言 一个C ...
- Rust 中的继承与代码复用
在学习Rust过程中突然想到怎么实现继承,特别是用于代码复用的继承,于是在网上查了查,发现不是那么简单的. C++的继承 首先看看c++中是如何做的. 例如要做一个场景结点的Node类和一个Sprit ...
随机推荐
- Oracle之SQL限定查询
WHERE限定条件 /*语法结构:SELECT * | 列名1[,列名2...] | 表达式FROM 表名 WHERE 限定条件; */ --查询职位为CLERK的员工信息 SELECT * FROM ...
- Oracle 添加用户并赋权,修改密码,解锁,删除用户的方法
转至:https://www.jb51.net/article/20367.htm 添加用户(随着用户的创建,自动产生与用户同名的schema) CREATE USER "TESTER&qu ...
- 文件上传漏洞靶机upload-labs(1到10)
前言 项目地址:https://github.com/c0ny1/upload-labs pass-01(前端验证) 绕过方法:https://www.cnblogs.com/bk76120/p/12 ...
- 初识html及网络爬虫概念
网络爬虫 HTML超文本标记语言 HTTP协议 简单的网络请求 python模块模拟浏览器发送请求 爬虫小案例 爬虫简介 我们一般情况 都是通过浏览器正常访问服务端获取资源浏览器展示给用户看 爬虫 模 ...
- pandas模块篇(终章)及初识mataplotlib
今日内容概要 时间序列 针对表格数据的分组与聚合操作 其他函数补充(apply) 练习题(为了加深对DataFrame操作的印象) mataplotlib画图模块 今日内容详细 时间序列处理 时间序列 ...
- Lesson A puma at large
新概念三 Lesson 1 A puma at large 词汇: 1. spot 易混淆: recognize v. [认出], identify v. [识别sb/sth的身份] v. 看出,发现 ...
- 在centos7下安装gitlab-runner
1.下载安装包 wget -O /usr/local/bin/gitlab-runner https://gitlab-ci-multi-runner-downloads.s3.amazonaws.c ...
- CentOS下mysql常用命令
CentOS下mysql常用命令 1.开启和关闭 1.1.开启 service mysql start 1.2.关闭 service mysql stop 1.3.重启 service mysql ...
- 移动端ios网页版收起键盘导致页面空白解决办法
失焦的时候把窗口滚动位置设置到(0,0)就行了 <input type="text" onblur="window.scrollTo(0, 0);"> ...
- VUE3 之 状态动画 - 这个系列的教程通俗易懂,适合新手
1. 概述 老话说的好:不用羡慕别人,每个人都有属于自己的人生道路,重要的是在前进道路上遇见阻碍时,如何去积极的面对并解决. 言归正传,今天我们来聊聊 VUE 的状态动画. 2. 状态动画 2.1 数 ...