在 Rust 中应该如何进行指针算术?

2024-04-16

我知道答案是“你不应该”......但为了争论,如何should你做吧?

例如,如果您想编写一个替代方案Vec<T>效果不同。

我发现你可以通过转化来制作“可以编译和运行的东西”* mut T值转化为u64并添加到它们中,然后将它们转换回* mut T并读取指针处的值(参见下面的示例)。它似乎有效,但留下了一些悬而未决的问题:

  1. Will a * mut T指针总是适合u64?

  2. Does write()当数据是任意(即不是托管类型)数据块时,指向不安全指针会触发指针别名问题libc:calloc?

  3. 这仅有效,因为我使用的是原始类型(f64)。如果这是一个真实的数据对象,我将不得不forget()首先是对象;但你能简单地write() a * mut T进入目标然后快乐地read()如果类型很复杂并且有子记录,稍后再输出?

  4. 这真的是正确的做法吗?看起来非常别扭。我本以为会发现一些不安全的地方ptrtoint() / inttoptr()一对,但我找不到类似的东西。

Example

extern crate libc;

use std::mem::size_of;
use std::ptr::write;
use std::ptr::read;
use std::mem::transmute;

use libc::calloc;
use libc::free;
use libc::c_void;

struct Array {
    length: usize,
    data: *mut f64,
}

impl Array {
    fn new(length: usize) -> Array {
        unsafe {
            Array {
                length: length,
                data: calloc(size_of::<f64>(), length) as *mut f64,
            }
        }
    }

    fn set(&mut self, offset: usize, value: f64) {
        if offset < self.length {
            unsafe {
                let root: *mut f64 = transmute(transmute::<*mut f64, u64>(self.data) +
                                               (size_of::<f64>() * offset) as u64);
                println!("Write: [{:?}] -> {}", root, value);
                write(root, value);
            }
        } else {
            println!("Write: Nope: [{}] is out of bounds", offset);
        }
    }

    fn get(&self, offset: usize) -> f64 {
        if offset < self.length {
            unsafe {
                let root: *const f64 = transmute(transmute::<*mut f64, u64>(self.data) +
                                                 (size_of::<f64>() * offset) as u64);
                let rtn = read::<f64>(root);
                println!("Read: [{:?}] -> {}", root, rtn);
                return rtn;
            }
        }
        println!("Read: Nope: [{}] is out of bounds", offset);
        0.0
    }
}

impl Drop for Array {
    fn drop(&mut self) {
        unsafe {
            free(self.data as *mut c_void);
        }
    }
}

fn main() {
    let mut tmp = Array::new(4);
    tmp.set(0, 100.5);
    tmp.set(1, 101.5);
    tmp.set(2, 102.5);
    tmp.set(3, 103.5);
    tmp.set(4, 104.5);
    tmp.get(0);
    tmp.get(1);
    tmp.get(2);
    tmp.get(3);
    tmp.get(4);
}

Output

Write: [0x7f04bdc1e080] -> 100.5
Write: [0x7f04bdc1e088] -> 101.5
Write: [0x7f04bdc1e090] -> 102.5
Write: [0x7f04bdc1e098] -> 103.5
Write: Nope: [4] is out of bounds
Read: [0x7f04bdc1e080] -> 100.5
Read: [0x7f04bdc1e088] -> 101.5
Read: [0x7f04bdc1e090] -> 102.5
Read: [0x7f04bdc1e098] -> 103.5
Read: Nope: [4] is out of bounds

指针有一个offset method https://doc.rust-lang.org/std/primitive.pointer.html#method.offset用于指针算术。

fn main() {
    let items = [1usize, 2, 3, 4];

    let ptr = &items[1] as *const usize;

    println!("{}", unsafe { *ptr });
    println!("{}", unsafe { *ptr.offset(-1) });
    println!("{}", unsafe { *ptr.offset(1) });
}

Output

2
1
3

https://doc.rust-lang.org/nightly/book/first-edition/unsafe.html https://doc.rust-lang.org/nightly/book/first-edition/unsafe.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Rust 中应该如何进行指针算术? 的相关文章

随机推荐

  • 如何使用数据列表比较并返回数据

    我是 Haskell 的新手 我正在努力寻找一种使用类成员变量来返回我正在寻找的成员变量的方法 我有这个数据 data Place Place name String north Float east Float rainfall Int
  • 奥尔森 时区 到 windows

    我需要在 Windows 中从奥尔森时区转换时区 使用PHP 我找到了这个http unicode org repos cldr trunk common supplemental windowsZones xml http unicode
  • 用于搜索 Google 云端硬盘的 Google Apps 脚本

    是否可以使用 Google Apps 脚本在 Google 云端硬盘中搜索文档和文件夹 谷歌已经取消了自己的文档 驱动器搜索小工具 因为它似乎依赖于 iGoogle 谷歌企业支持也承认了这一点 谢谢 我想你正在寻找搜索文件 https de
  • Unity使用Invoke在另一个脚本上调用方法

    我有两个脚本 其中一个重新启动场景 另一个是倒计时器 而不是在第一个脚本中调用重新启动场景方法 但是 它没有重新启动 即使没有错误 我也不明白为什么 重新启动场景的第一个脚本 using UnityEngine using UnityEng
  • 在编译时通过 constexpr 或模板函数获取多维 std::array 的大小

    我用的是三维std array 因为大小在编译时已知 但是 我注意到 size 函数不是静态的 因此 constexpr 模板函数无法访问 我已经找到了下面的演示示例 它估计一维的大小std array 然而 这不适用于二维或更多维度 有没
  • C# 中的并发集合

    我正在寻找一种方法来获得并发收集 in C 或者至少是一个支持的集合并发枚举器 现在我得到了InvalidOperationException当我正在迭代的集合发生变化时 我可以深度复制该集合并使用私人副本 但我想知道是否有更好的方法 代码
  • DisplayMemberPath 在 WPF 中不起作用

    我要显示CustomerList CustomerName财产项目ListBox using ItemsSource DisplayMemberPath仅限财产 但它不起作用 我不想使用DataContext或我的问题中的任何其他绑定 请帮
  • 实体框架 6 和集合

    我正在开发我的第一个实体框架应用程序 我正在使用 EF 版本 6 来自 Nuget 和 net 4 0 然而 我在一些对我来说似乎应该非常简单的事情上遇到了一些困难 我在互联网上发现了很多相互矛盾的建议和解决方案 但是在花了几天时间尝试解决
  • Firebase - Firestore - 使用 collection.add() 获取密钥

    我在使用 Firebase 的新 Firestore 时遇到问题 情况 我有一个collection room 我创建房间collection room add room 我正在尝试做的事情 我需要更新一个房间 为此 我使用 collect
  • 示例 urllib3 和 python 中的线程

    我正在尝试在简单线程中使用 urllib3 来获取多个 wiki 页面 该脚本将 为每个线程创建 1 个连接 我不明白为什么 并永远挂起 urllib3 和线程的任何提示 建议或简单示例 import threadpool from url
  • 将多行转换为一行,并以逗号作为分隔符[重复]

    这个问题在这里已经有答案了 如果我发出SELECT username FROM Users我得到这个结果 username Paul John Mary 但我真正需要的是one所有值均以逗号分隔的行 如下所示 Paul John Mary
  • 计算网格上两点之间恰好有“n”个节点的最短路径

    我在网格上定义了以下 3D 表面 pylab inline def muller potential x y use numpy False Muller potential Parameters x float np ndarray or
  • 实体框架 Fluent API 映射简单的一对多关系

    我有两张桌子 文档 Id DocumentTypeId 标题 详细信息 文档类型 ID 名称 描述 DocumentTypeId 是引用 DocumentTypes 表的外键 IE 所有文件都可以应该 有一个分配给它们的类型 我有两节课 p
  • 多人台球游戏物理模拟[关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 将邻接矩阵转换为 Cytoscape 的 Edgelist(csv 文件)

    我的 csv 文件中有一个大的 200 列 行 邻接矩阵 这详细说明了个体之间的互动 我想将此文件转换为边缘列表 可以手动完成 但需要大量时间 下面显示了一小部分数据 第一个单元格是空格 A B C A 0 0 1 B 0 0 1 C 1
  • (0, _reactI18next.translate) 不是函数

    实际上 我是本地反应新手 在这里我尝试使用 react i18next 将语言更改为阿拉伯语 但在执行时出现以下错误 ReactNativeJS 0 reactI18next translate 不是一个函数 在 0 reactI18nex
  • AppDelegate 或 AppController

    在阅读可可教程时 我注意到一些教程使用AppDelegate还有一些AppController用于定义IBActions打开使用子类的各种窗口NSWindowController 这有某种经验法则吗 我创建一个仅是我的应用程序委托的类 并实
  • 如何使用 Visual Studio 2008 对 C# Web 服务进行单元测试

    您应该如何使用 Visual Studio 2008 对 C 中的 Web 服务进行单元测试 当我生成单元测试时 它会添加对 Web 服务类的实际引用 而不是 Web 引用 它设置以下中指定的属性 http msdn microsoft c
  • 检查 netcdf linux 库版本

    如何确定我的系统中安装了哪个版本的 netcdf 库 有命令行吗 我尝试搜索 netcdf 发现了一堆文件 但无法确定版本号 有没有命令可以检查已安装的任何版本 我在ubuntu上 netCDF 提供nc config用于此目的的命令行工具
  • 在 Rust 中应该如何进行指针算术?

    我知道答案是 你不应该 但为了争论 如何should你做吧 例如 如果您想编写一个替代方案Vec