repr(Rust)

首先,所有类型都有一个以字节为单位的对齐方式,一个类型的对齐方式指定了哪些地址可以用来存储该值。一个具有对齐方式n的值只能存储在n的倍数的地址上。所以对齐方式 2 意味着你必须存储在一个偶数地址,而 1 意味着你可以存储在任何地方。对齐至少是 1,而且总是 2 的幂。

基础类型通常按照其大小对齐,尽管这是特定平台的行为。例如,在 x86 上u64f64通常被对齐到 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的更多相关文章

  1. Rust 中的数据布局--可选的数据布局

    Rust 允许你指定不同于默认的数据布局策略,并为你提供了不安全代码指南. repr(C) 这是最重要的"repr".它的意图相当简单:做 C 所做的事.字段的顺序.大小和对齐方式 ...

  2. Rust 中的数据布局--非正常大小的类型

    非正常大小的类型 大多数的时候,我们期望类型在编译时能够有一个静态已知的非零大小,但这并不总是 Rust 的常态. Dynamically Sized Types (DSTs) Rust 支持动态大小 ...

  3. 借助 SIMD 数据布局模板和数据预处理提高 SIMD 在动画中的使用效率

    原文链接 简介 为发挥 SIMD1 的最大作用,除了对其进行矢量化处理2外,我们还需作出其他努力.可以尝试为循环添加 #pragma omp simd3,查看编译器是否成功进行矢量化,如果性能有所提升 ...

  4. 【译】对Rust中的std::io::Error的研究

    原文标题:Study of std::io::Error 原文链接:https://matklad.github.io/2020/10/15/study-of-std-io-error.html 公众 ...

  5. 如何在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 ...

  6. 在 ASP.NET 中创建数据访问和业务逻辑层(转)

    .NET Framework 4 当在 ASP.NET 中处理数据时,可从使用通用软件模式中受益.其中一种模式是将数据访问代码与控制数据访问或提供其他业务规则的业务逻辑代码分开.在此模式中,这两个层均 ...

  7. WPF中的数据验证

    数据验证 WPF的Binding使得数据能够在数据源和目标之间流通,在数据流通的中间,便能够对数据做一些处理. 数据转换和数据验证便是在数据从源到目标 or 从目标到源 的时候对数据的验证和转换. V ...

  8. c++继承中的内存布局

    今天在网上看到了一篇写得非常好的文章,是有关c++类继承内存布局的.看了之后获益良多,现在转在我自己的博客里面,作为以后复习之用. ——谈VC++对象模型(美)简.格雷程化    译 译者前言 一个C ...

  9. Rust 中的继承与代码复用

    在学习Rust过程中突然想到怎么实现继承,特别是用于代码复用的继承,于是在网上查了查,发现不是那么简单的. C++的继承 首先看看c++中是如何做的. 例如要做一个场景结点的Node类和一个Sprit ...

随机推荐

  1. 每日一算之变位词(C#)

    今天看编程珠玑里面,看到一个关于查找变位词的题目,大概意思如下:post,stop,tops这几个是变位词,找出类似的这些词语来. 解题思路一:既然是变位词,1.他们的长度一定是一致的:2.还有就是他 ...

  2. startActivityForResult跳转后回调数据

    从AActivity向BActivity跳转后,关闭BActivity并向AActivity回调一些数据: 建立AActivity.java文件: 1 public class AActivity e ...

  3. xsd文件生成cs文件命令

    C:\Windows\System32>xsd.exe c:/Createst.xsd -c C:\Windows\System32>xsd.exe c:/Creauest.xsd /c ...

  4. LabVIEW,控件快捷菜单,温度转换

    目前正在自学LabVIEW,深感困难重重,我将偶尔发表一些自己的收获,自认为算是干货了, 搜到这篇随笔的朋友们或多或少遇到了些许困难,希望这能帮助到你们. 内容:练习使用LabVIEW中的控件快捷菜单 ...

  5. SQL从零到迅速精通【实用函数(3)】

    1.LOWER()函数 使用LOWER函数将字符串中所有字幕字符转换为小写,输入语句如下. SELECT LOWER('BEAUTIFUL'),LOWER('Well'); 2.UPPER()函数 S ...

  6. laravel 实现详情分页

    选择合适的PHP框架及前端框架布局页面(10分) 首先展示出分类列表,每个分类下只显示3条信息,无需分页 (30分) 在列表页 点击文章标题进入详细页面,对应的文章点击量+1(30分) 在详细页面点击 ...

  7. python学习之numpy实战

    import numpy as np def main(): lst=[[1,3,5],[2,4,6]] print('hello world') print(type(lst)) np_lst = ...

  8. IDEA版部署离线ArcGIS api for JavaScript

    痛苦!折磨! 这两天发现IDEA 做ArcGIS api 开发比EClipse好用(重点是没有JS提示).但引入的ArcGIS api 一直报错,说找不到.这两天思来想去就是不知道为什么找不到loca ...

  9. C语言知识点的实例

    编译环境:Visual Studio 2012 编程语言:C @ 目录 1.memcpy与'/0' 2.volatile的使用 3.数字转字符 4.memcpy len 与指针加减 len 的区别 5 ...

  10. ansible 一 简介和部署

    一.Ansible的介绍 Ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet.cfengine.chef.func.fabric)的优点.实现了批量系统配置 ...