HiveBrain v1.2.0
Get Started
← Back to all entries
patternrustMajor

How should you do pointer arithmetic in Rust?

Submitted by: @import:stackoverflow-api··
0
Viewed 0 times
youhowpointerarithmeticshouldrust

Problem

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

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

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:

-
Will a * mut T pointer always fit into u64?

-
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?

-
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?

-
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.

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::(), length) as *mut f64,
}
}
}

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

fn get(&self, offset: usize) -

Solution

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


Output

2
1
3


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

Code Snippets

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

Context

Stack Overflow Q#24759028, score: 87

Revisions (0)

No revisions yet.