Я знаю, что ответ "вы не должны"... но ради аргумента, как вы это делаете?
Например, если вы хотите написать альтернативу Vec<T>
, которые работают по-другому.
Я вижу, что вы можете сделать "что-то, что компилируется и запускается", преобразовывая значения * mut T
в u64
и добавляя к ним, а затем передавая их обратно в * mut T
и считывая значение в указателе (см. пример ниже). Кажется, он работает, но он оставляет несколько открытых вопросов:
-
Будет ли указатель
* mut T
всегда вписываться вu64
? -
Выполняет ли
write()
обращение к небезопасным вопросам смены указателя триггера указателя, когда данные представляют собой произвольный (то есть не управляемый тип) блок данных изlibc:calloc
? -
Это работает только потому, что я использую примитивный тип (
f64
). Если бы это был реальный объект данных, мне пришлось быforget()
объект сначала; но можете ли вы простоwrite()
a* mut T
в цель, а затем счастливоread()
повторить это позже, если тип является сложным и имеет дочерние записи? -
Это действительно правильный способ сделать это? Это кажется крайне неудобным. Я ожидал найти небезопасную пару
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