To dereference a raw pointer, we must use unsafe code. What are the situations in which raw pointers can be used (and can be useful) in ways that don't involve using unsafe code at all?
Pretty much the only thing you can do is cast the raw pointer to an usize. You can use that to do stuff like getting the index in an array from a reference into the array.
fn get_index_in_array(array: &[i32], item: &i32) -> usize {
let array_ptr: *const i32 = array.as_ptr();
let item_ptr: *const i32 = item;
let distance = ((item_ptr as usize) - (array_ptr as usize)) / std::mem::size_of::<i32>();
assert!(distance < array.len());
distance
}
fn main() {
let arr = [1, 2, 3, 4];
println!("{}", get_index_in_array(&arr, &arr[2]));
}
2
Related
Can someone explain the difference between &v[0] versus v[0] where v is a Vector? If I were to guess it is similar to "borrowing" versus "moving", however the following examples would suggest a different reason.
1)
You can access the vector items by referring to the index number:
let mut data = vec![5, 10, 15];
let first = &data[0];
println!("The first element is {}", first);
To change the value of a specific item, refer to the index number:
let mut data = vec![5, 10, 15];
data[0] = 15;
Why not &data[0] in example 2, and the opposite in example 1? Will data be moved if the type inside the vector did not implement Copy trait?
PS: I'm coming from C++ background.
The square bracket indexing syntax automatically derefs the result returned from the Index or IndexMut trait. They resolve to the value stored in the data structure, and you have to explicitly reference in order to get a reference instead.
This means your examples desugar to this
// needed for explicit `index` and `index_mut`
use std::ops::{Index, IndexMut};
let mut data = vec![5, 10, 15];
let first = &{ *data.index(0) }; // first has type `&i32`
println!("The first element is {}", first);
data[0] = 15; // assignment is always done through IndexMut
*data.index_mut(0) = 15;
let mut_ref: &mut i32 = &mut data[i]; // also desugars to IndexMut
let mut_ref: &mut i32 = data.index_mut(i);
let imm_ref: &i32 = &data[i]; // desugars to Index
let imm_ref: &i32 = data.index(i);
let val: i32 = data[i]; // desugars to dereferenced Index
let val: i32 = *data.index(i);
For your examples, which use integers (which are a Copy type meaning that they can still be used after moves), there's really no reason to take a reference instead of just doing data[i] in the first case.
How can I convert a mutable u8 pointer to a mutable reference of another type?
let ptr: *mut u8;
let reference: &mut SomeType = ?; // What should i do here?
I have found a sort-of viable solution, but I wonder if there is a better way:
let reference = unsafe { &mut *(ptr as *mut SomeType) };
You have already found an acceptable method. A slightly preferable one is to use pointer::cast instead of as, because that explicitly specifies that you are trying to change the type of the referent and not any of the many other things as can do.
let ptr = ptr.cast::<SomeType>();
let reference = unsafe { &mut *ptr };
Do not use std::mem::transmute for this. Transmuting should always be the last resort in any circumstance (the nomicon and function documentation say so!), because it reinterprets the bytes regardless of what they are — in this case it'll convert any pointer-sized value, such as a reference to the pointer. By sticking with cast and &*, we catch more possible type errors. (Clippy even has a default lint against using transmute here.)
You could use std::mem::transmute instead:
use std::mem::transmute;
#[repr(transparent)]
struct SomeStruct(u8);
fn main() {
let a = &mut 10u8;
let ptr = a as *mut u8;
let reference: &mut SomeStruct = unsafe { transmute(ptr) };
}
I'm writing a c-binding to a Rust function. The Rust function takes a 3D slice where 2 dimensions are of size two. Essentially it's a slice of 2D line segments where a line segment is represented by 2 points.
This means the segments have type:
segments: [[[f32; 2]; 2]]
Now since I call this from C I only have a simple f32 pointer at the FFI boundary. My multi-dimensional array from c is in row-major memory order which I understand matches what Rust would expect. So morally I should be able to say to rust: It's just that type.
I have looked at https://doc.rust-lang.org/std/ptr/fn.slice_from_raw_parts.html but I don't see how I can handle a more complex structure with that.
So to make it very concrete I want to be able to call foo from foo_c and foo should handle the conversion from pointer to the 3D slice/array structure.
#[no_mangle]
pub unsafe extern fn foo_c(segments: *f32, n_segments: usize) {
foo(...)
}
fn foo(segments: [[[f32; 2]; 2]]) {
...
}
If possible I would like to do this without copying any data around.
Any help is appreciated!
First I think you made some typos, so I'm assuming your code is:
#[no_mangle]
// missing `const`
pub unsafe extern fn foo_c(segments: *const f32, n_segments: usize) {
foo(...)
}
// missing `&`
fn foo(segments: &[[[f32; 2]; 2]]) {
...
}
The solution is:
#[no_mangle]
pub unsafe extern fn foo_c(segments: *const f32,n_segments: usize) {
// first we cast the pointer to get the slice `T`
// so from a generic `*const f32` to `*const T` where T is `[[f32; 2]; 2]`
let ptr = segments as *const [[f32; 2]; 2];
// we construct the slice using `slice_from_raw_parts`
// after we got the correct pointer.
let segments_slice = std::ptr::slice_from_raw_parts::<[[f32;2];2]>(ptr,n_segments);
// we still have `*const [[f32; 2]; 2]` which we need to convert
// to `&[[f32; 2]; 2]` so we use `&*` (dereference then borrow).
foo(&*segments_slice)
}
fn foo(segments: &[[[f32; 2]; 2]]) {
println!("segments {:?}",segments);
}
I'm admittedly new to Rust. That being said, this doesn't make sense to me yet finding out why the behavior I'm seeing isn't what I expect seems like a good learning opportunity:
use std::iter::Enumerate;
use std::collections::HashMap;
impl Solution {
pub fn two_sum(nums: Vec<i32>, target: i32) -> Vec<i32> {
let mut numToI: HashMap<i32, usize> = HashMap::new();
for (i,v) in nums.iter().enumerate() {
let num: i32 = *v;
let complement: i32 = target - num;
if numToI.contains_key(complement) {
return vec![i as i32, numToI.get(complement) as i32];
} else {
numToI.insert(complement, i);
}
}
return vec![-1,-1];
}
}
Here I'm doing the simple question twoSum. I understand that nums.iter().enumerate() will return the values i and v, which are of type usize and a pointer to the element in nums (so in this case a reference to an i32), respectively. The thing I'm having trouble with is that although I specify numToI is a HashMap<i32, usize>, not HashMap<&i32, usize>, and I dereference to get the value of v with *v and assign the value to num, when I check if the HashMap numToI contains this i32 dereferenced value as a key, I get the error: expected &i32, found i32 on the call to contains_key. Why is this? Is it because the HashMap type always requires a pointer rather than a raw value, or is it due to an intricacy of Rust I'm not aware of? Shouldn't it expect a pointer for the key instead of a i32 if I had used HashMap<&i32, i32>?
More importantly, if this is due to a difference between Rust and C that has to do with the way borrowing etc. is used in Rust, where can I learn more about the intricacies of these differences?
contains_key takes a reference. It doesn't need to take ownership of the value to test with - it just needs to look at it temporarily.
Rust is complaining that you are passing in an i32 by value instead of a reference to it. It should tell you to borrow instead: numToI.contains_key(&complement).
That's the only issue with your code, really. HashMap keys don't need to be references, and it would be really inconvenient if they did.
I've read that pointer arithmetic in Rust can be done through the pointer.offset() function, but it always has to be implemented in unsafe code:
fn main() {
let buf: [u32; 5] = [1, 2, 3, 4, 5];
let mut ptr1: *const u32 = buf.as_ptr();
unsafe {
let ptr2: *const u32 = buf.as_ptr().offset(buf.len() as isize);
while ptr1 < ptr2 {
println!("Address {:?} | Value {}", ptr1, *ptr1);
ptr1 = ptr1.offset(1);
}
}
}
If I want to code in Rust securely, should I code without using pointer arithmetic and just using the corresponding index of an array for example? Or is there any other way?
If I want to code in Rust securely
Then you should not use unsafe. There are a few legit reasons for unsafe (e.g. accessing memory locations that are known and safe to use, e.g. on microcontrollers several registers), but generally you should not use it.
should I code without using pointer arithmetic and just using the corresponding index of an array for example
Yes. There is no reason (in this specific case) to use unsafe at all. Just use
for i in 0..buf.len() {
println!("Value {}", buf[i]);
}
This code however is not considered as "rusty", instead use a for-loop
for i in &buf {
println!("Value {}", i);
}
Using raw pointers like that is very unlikely[1] to be faster than an idiomatic for loop over an iterator:
fn main() {
let buf: [u32; 5] = [1, 2, 3, 4, 5];
for val in buf.iter() {
println!("Address {:?} | Value {}", val as *const u32, val);
}
}
This is also much easier to read and doesn't introduce memory unsafety risks.
1 In fact, your code compares two pointer values each iteration, so is likely to be much slower than the idiomatic for loop, which can often omit all bounds checks.