你应该如何在 Rust 中进行指针运算? [英] How should you do pointer arithmetic in Rust?

查看:105
本文介绍了你应该如何在 Rust 中进行指针运算?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道答案是你不应该"……但是为了争论,你应该如何做到这一点?

I know the answer is "you shouldn't"... but for the sake of argument, how should you do it?

例如,如果您想编写一个以不同方式工作的 Vec 的替代方案.

For example, if you wanted to write an alternative to Vec<T> that worked differently.

我看到您可以通过将 * mut T 值转换为 u64 并添加到它们,然后将它们转换回 * mut T 并读取指针处的值(参见下面的示例).它似乎有效,但它留下了一些悬而未决的问题:

I see that you can make 'something that compiles and runs' by transmuting * mut T values into u64 and adding to them, then transmuting them back into * mut T and reading the value at the pointer (see example below). It seems to work, but it leaves a few of open questions:

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

  1. Will a * mut T pointer always fit into u64?

当数据是来自 libc:callocwrite() 是否会触发指针别名问题代码>?

Does write()ing to an unsafe pointer trigger pointer aliasing issues when the data is an arbitrary (i.e. not a managed type) data block from libc:calloc?

这只是因为我使用的是原始类型 (f64).如果这是一个真实的数据对象,我必须先forget() 该对象;但是你可以简单地 write() 一个 * mut T 到一个目标中,然后愉快地 read() 如果类型很复杂,稍后再把它写出来并且有子记录?

This only works because I'm using a primitive type (f64). If this was a real data object, I would have to forget() the object first; but can you simply write() a * mut T into a target and then happily read() it out again later if the type is complex and has child records?

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

Is this really the right way of doing this? It seems extremely awkward. I was expecting to find some unsafe ptrtoint() / inttoptr() pair, but I can't find anything like that.

示例

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 方法,用于指针运算.

Pointers have an offset method for pointer arithmetic.

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 中进行指针运算?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆