rust - 你应该如何在 Rust 中进行指针运算?

标签 rust

我知道答案是“你不应该”...但是为了争论,你应该怎么做?

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

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

  1. 请问* mut T指针总是适合 u64 ?

  2. 是否 write()当数据是来自 libc:calloc 的任意(即非托管类型)数据 block 时,对不安全指针触发指针别名问题?

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

  4. 这真的是正确的做法吗?显得格外别扭。我期待找到一些不安全的 ptrtoint()/inttoptr()对,但我找不到类似的东西。

例子

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);
}

输出

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用于指针运算。

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) });
}

输出

2
1
3

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

关于rust - 你应该如何在 Rust 中进行指针运算?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24759028/

相关文章:

rust - 生存期和异步FN的问题

rust - 无法将特征方法纳入范围

rust - 如何在 Rust 的同一个 lib.rs 文件中的测试中引用常量?

rust - 解决通过引用获取参数的闭包的类型不匹配

rust - 没有预建的 wasm-opt 二进制文件

rust - 带引脚和不带引脚的比较功能

rust - 如何在Rust中将借来的值保存到struct字段中

rust - 字符串串联在使用rust 和借用中

rust - 如何获得 syntax::ast::Ident 的绝对名称?

rust - 如何计算两个 Rust 数组/切片/向量的点积?