Есть ли универсальный тип указателя Rust, который может хранить любой другой тип указателя, аналог C void *? - PullRequest
0 голосов
/ 04 июня 2019

Я хочу создать C FFI API для своего ящика, но неясно, насколько безопасно использовать указатели.Псевдокод:

#[no_mangle]
extern "C" fn f(...) -> *mut c_void {
    let t: Box<T> = ...;
    let p = Box::into_raw(t);
    p as *mut c_void
}

Это работает, как и ожидалось, но насколько это безопасно?В C или C ++ есть специальный указатель void *, и стандарт C ++ объявляет, что его можно безопасно привести к нему.Потенциально, sizeof(void *) может быть не равно sizeof(T *), но есть гарантия, что sizeof(void *)> = sizeof(T *).

А как насчет Rust?Есть ли какая-либо гарантия относительно std::mem::size_of указателя или безопасного приведения между указателями?Или все указатели имеют одинаковый размер по реализации, равный usize?

Под «универсальным» я подразумеваю, что вы можете конвертировать X *, не теряя ничего.Меня не волнует информация о типах;Меня интересуют разные размеры указателей на разные вещи, такие как near / far указатели в 16-битных днях.

4.10 говорит:

Результат преобразования "указатель на cv T «указатель на cv void» указывает на начало хранилища, в котором находится объект типа T,

Невозможно, чтобы sizeof(void *) < sizeof(T *), потому что тогда этоневозможно иметь реальный адрес места хранения.

1 Ответ

4 голосов
/ 04 июня 2019

номер

Сырые указатели Rust (и ссылки) в настоящее время бывают двух видов:

  • тонкий (одно целое по размеру)
  • жирный (два целых числа натурального размера)
use std::mem;

fn main() {
    println!("{}", mem::size_of::<*const u8>());   //  8
    println!("{}", mem::size_of::<*const [u8]>()); // 16
}

Там нет типа, который позволяет хранить оба; даже Большой Молот mem::transmute не будет работать:

use std::mem;

unsafe fn example(mut thin: *const u8, mut fat: *const [u8]) {
    fat = mem::transmute(thin);
    thin = mem::transmute(fat);
}
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
 --> src/main.rs:4:11
  |
4 |     fat = mem::transmute(thin);
  |           ^^^^^^^^^^^^^^
  |
  = note: source type: `*const u8` (64 bits)
  = note: target type: `*const [u8]` (128 bits)

error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
 --> src/main.rs:5:12
  |
5 |     thin = mem::transmute(fat);
  |            ^^^^^^^^^^^^^^
  |
  = note: source type: `*const [u8]` (128 bits)
  = note: target type: `*const u8` (64 bits)

Поскольку расположение указателей жира является концепцией Rust, к ним никогда не следует обращаться через FFI. Это означает, что следует использовать только тонкие указатели, все из которых имеют одинаковый известный размер.

Смотри также:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...