Rust 允许你指定不同于默认的数据布局策略,并为你提供了不安全代码指南

repr(C)

这是最重要的“repr”。它的意图相当简单:做 C 所做的事。字段的顺序、大小和对齐方式与你在 C 或 C++ 中期望的完全一样。任何你期望通过 FFI 边界的类型都应该有repr(C),因为 C 是编程世界的语言框架。这对于合理地使用数据布局做更多的技巧也是必要的,比如将值重新解释为不同的类型。

我们强烈建议使用rust-bindgen和/或cbindgen来为你管理 FFI 的边界。Rust 团队与这些项目紧密合作,以确保它们能够稳健地工作,并与当前和未来关于类型布局和 reprs 的保证兼容。

必须记住repr(C)与 Rust 更奇特的数据布局功能的互动。由于它具有“用于 FFI”和“用于布局控制”的双重目的,repr(C)可以应用于那些如果通过 FFI 边界就会变得无意义或有问题的类型:

  • ZST 仍然是零大小,尽管这不是 C 语言的标准行为,而且明确违背了 C++ 中空类型的行为,即它们仍然应该消耗一个字节的空间
  • DST 指针(宽指针)和 tuple 在 C 语言中没有对应的概念,因此从来不是 FFI 安全的
  • 带有字段的枚举在 C 或 C++ 中也没有对应的概念,但是类型的有效桥接是被定义的
  • 如果T是一个FFI 安全的非空指针类型Option<T>被保证具有与T相同的布局和 ABI,因此也是 FFI 安全的。截至目前,这包括&&mut和函数指针,所有这些都不能为空。
  • repr(C)而言,元组结构和结构一样,因为与结构的唯一区别是字段没有命名。
  • repr(C)相当于无字段枚举的repr(u*)之一(见下一节)。选择的大小是目标平台的 C 应用二进制接口(ABI)的默认枚举大小。请注意,C 语言中的枚举表示法是实现定义的,所以这实际上是一个“最佳猜测”。特别是,当对应的 C 代码在编译时带有某些标志时,这可能是不正确的。
  • 带有repr(C)repr(u*)的无字段枚举仍然不能在没有相应变量的情况下设置为整数值,尽管这在 C 或 C++ 中是允许的行为。如果(不安全地)构造一个枚举的实例,但不与它的一个变体相匹配,这是未定义的行为(这使得详尽的匹配可以继续被编写和编译为正常行为)。

repr(transparent)

这只能用于具有单个非零尺寸字段的结构(可能还有其他零尺寸字段)。其效果是,整个结构的布局和 ABI 被保证与该字段相同。

我们的目标是使单一字段和结构之间的转换成为可能。一个例子是UnsafeCell,它可以被转换为它所包装的类型。(UnsafeCell也用了一个不稳定的特性no_niche,所以当它嵌套其它类型的时候,它的 ABI 也并没有一个稳定的保证。)

另外,通过 FFI 传递结构,其中内部字段类型在另一端被期望,这保证了结构的工作。特别是,这对于struct Foo(f32)总是具有与f32相同的 ABI 是必要的。

只有在唯一的字段为pub或其内存布局在文档中所承诺的情况下,该 repr 才被视为一个类型的公共 ABI 的一部分。否则,该内存布局不应被其他 crate 所依赖。

更多细节可以参考RFC

repr(u*), repr(i*)

这些指定了使无字段枚举的大小。如果判别符超过了它可以容纳的整数,就会产生一个编译时错误。你可以通过将溢出的元素明确设置为 0 来手动要求 Rust 允许这样做。

术语“无字段枚举”仅意味着该枚举在其任何变体中都没有数据。没有repr(u*)repr(C)的无字段枚举仍然是一个 Rust 本地类型,没有稳定的 ABI 表示。添加repr会使它在 ABI 上被视为与指定的整数大小完全相同。

如果枚举有字段,其效果类似于repr(C)的效果,因为该类型有一个定义的布局。这使得将枚举传递给 C 代码或者访问该类型的原始表示并直接操作其标记和字段成为可能,详见RFC

这些“repr”对结构(struct)没有作用。

在含有字段的枚举中加入明确的repr(u*)repr(i*)repr(C)可以抑制空指针优化,比如:

 

enum MyOption<T> {
Some(T),
None,
} #[repr(u8)]
enum MyReprOption<T> {
Some(T),
None,
} assert_eq!(8, size_of::<MyOption<&u16>>());
assert_eq!(16, size_of::<MyReprOption<&u16>>());

空指针优化针对无字段且拥有repr(u*)repr(i*)repr(C)的枚举仍然生效。

repr(packed)

repr(packed)强制 Rust 去掉任何填充,只将类型对齐到一个字节。这可能会改善内存占用,但可能会有其他负面的副作用。

特别是,大多数架构强烈地希望数值被对齐。这可能意味着不对齐的加载会受到惩罚(x86),甚至会出现故障(一些 ARM 芯片)。对于简单的情况,如直接加载或存储一个已打包的字段,编译器可能能够用移位和掩码来解决对齐问题。然而,如果你对一个已打包的字段进行引用,编译器就不太可能发出代码来避免无对齐的加载。

由于这可能导致未定义的行为,我们在 Lint 中已经实现了对应的检查,并且该行为会被认为是错误。

repr(packed)是不能轻易使用的,除非你有极端的要求,否则不应该使用这个。

这个 repr 是对repr(C)repr(Rust)的修改。

repr(align(n))

repr(align(n))(其中n是 2 的幂)强制类型至少按照 n 对齐。

这可以实现一些技巧,比如确保数组中的相邻元素不会彼此共享同一个缓存行(这可能会加快某些类型的并发代码)。

这是repr(C)repr(Rust)的一个修改版本,它与repr(packed)不兼容。

Rust 中的数据布局--可选的数据布局的更多相关文章

  1. Rust 中的数据布局-repr

    repr(Rust) 首先,所有类型都有一个以字节为单位的对齐方式,一个类型的对齐方式指定了哪些地址可以用来存储该值.一个具有对齐方式n的值只能存储在n的倍数的地址上.所以对齐方式 2 意味着你必须存 ...

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

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

  3. Ext2文件系统布局,文件数据块寻址,VFS虚拟文件系统

    注:本分类下文章大多整理自<深入分析linux内核源代码>一书,另有参考其他一些资料如<linux内核完全剖析>.<linux c 编程一站式学习>等,只是为了更好 ...

  4. Android常规布局(网络异常布局、空数据布局,未登录布局等)切换工具类,Layout切换

    本人已整理好发布到github,已优化. github地址:https://github.com/buhuiming/StatusLayoutManager 使用:compile 'com.bhm.s ...

  5. html中table表格标题固定表数据行出现滚动条

    需求 web系统中有的用户不喜欢分页,希望数据能在一个页面中全部显示出来. 但是页面中是有滚动条的,当查看下面的数据时就不知道数据行中的列对应的是哪个标题的列. 也就是无法知道这个列是什么数据. 所以 ...

  6. 分析 BAT 互联网巨头在大数据方向布局及大数据未来发展趋势

    > 风起云涌的大数据战场上,早已迎百花齐放繁荣盛景,各大企业加速跑向"大数据时代".而我们作为大数据的践行者,在这个"多智时代"如何才能跟上大数据的潮流, ...

  7. WebGIS中基于控制点库进行SHP数据坐标转换的一种查询优化策略

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.前言 目前项目中基于控制点库进行SHP数据的坐标转换,流程大致为:遍 ...

  8. OpenCV中IplImage图像格式与BYTE图像数据的转换

    最近在将Karlsruhe Institute of Technology的Andreas Geiger发表在ACCV2010上的Efficent Large-Scale Stereo Matchin ...

  9. Linq中使用反射实现--LINQ通用数据表绑定DataGrid控件的方法(原创)

    项目需求,因为项目中存在很多表,这些表的内容需要呈现给客户浏览.转载请注明出处 相信很多写过程序的设计者很容易的用以下方式实现 在SqlConnect ,DataSet 的方式,我们很轻松的可以通过S ...

随机推荐

  1. 针对python输入要求

    针对python输入要求 类型: 1.输入行数不确定,并且每一行输入一个数据. a=[] b=input() while b!='-1': //指随意使用一个值作为一个标志,来进行控制输入的行数.(在 ...

  2. Tableau绘制K线图、布林线、圆环图、雷达图

    Tableau绘制K线图.布林线.圆环图.雷达图 本文首发于博客冰山一树Sankey,去博客浏览效果更好.直接右上角搜索该标题即可 一. K线图 1.1 导入数据源 1.2 拖拽字段 将[日期]托到列 ...

  3. JZ-050-数组中重复的数字

    数组中重复的数字 题目描述 在一个长度为n的数组里的所有数字都在0到n-1的范围内. 数组中某些数字是重复的,但不知道有几个数字是重复的.也不知道每个数字重复几次.请找出数组中 第一个重复的数字. 例 ...

  4. tep完整教程帮你突破pytest

    持续维护的教程 tep教程会随着版本更新或经验积累,持续维护在电子书中,最新的最全的内容请锁定这篇文章[最新]tep完整教程帮你突破pytest: https://dongfanger.gitee.i ...

  5. tp6微信公众号开发者模式获取access_token

    1:config 文件下新建一个文件wechat.php,将个人id和秘钥写入配置文件 网址: https://developers.weixin.qq.com/doc/offiaccount/Bas ...

  6. vue 控制台错误

    控制台显示报错: Uncaught TypeError: WEBPACK_IMPORTED_MODULE_1_vuex.a.store is not a constructor 解决办法: 将new ...

  7. CF1392F题解

    首先题意很明显就不说了吧www 先说一下做这道题的经历 昨天下午和 blw 一起去食堂吃饭,和他产生了一点儿冲突,于是我考了一下他 P1119 (就是那道 Floyd),他很快做出来了,于是考了我这道 ...

  8. [递归回溯] LeetCode 504七进制数(摸鱼版)

    LeetCode 七进制数 前言: 这个就没什么好说的了 题目:略 步入正题 进位制转换 10 -n 余数加倒叙 没什么好讲的直接上七进制代码 偷个懒 10进位制转7 class Solution { ...

  9. ArcMap操作随记(6)

    1.上流汇流区 [填洼]→[流向]→[分水岭] 2.输入坐标进行移动,也就是精确移动 [移动]工具(在自定义中,其中的[旋转]工具也有类似效果) 3.找最近的要素(矢量) [近邻分析]→[汇总] 4. ...

  10. 内网渗透----Token 窃取与利用

    0x00 前言 在之前的文章<渗透技巧--程序的降权启动>介绍了使用 SelectMyParent 降权的方法,本质上是通过 token 窃取实现的.这一次将要对 token 窃取和利用做 ...