pointers - 是否有一种通用的 Rust 指针类型可以存储任何其他类型的指针,类似于 C 的 void *?

标签 pointers rust

我想为我的 crate 创建一个 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 说

The result of converting a "pointer to cv T" to a "pointer to cv void" points to the start of the storage location where the object of type T resides,

sizeof(void *) < sizeof(T *) 是不可能的, 因为那样就不可能有存储位置的真实地址。

最佳答案

没有。

Rust 的原始指针(和引用)目前有两种形式:

  • 瘦(一个原生大小的整数)
  • fat(两个自然大小的整数)
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 访问它们。这意味着只应使用细指针,所有细指针都具有统一的已知大小。

对于这些类型,您应该使用 opaque pointer 来提供更好的类型安全性。您还可以使用 *const ()*const libc::c_void

另见:

In C or C++, there is special void * pointer and the C++ standard declares that it is safe to cast to it.

这并不总是正确的:

关于pointers - 是否有一种通用的 Rust 指针类型可以存储任何其他类型的指针,类似于 C 的 void *?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56441791/

相关文章:

websocket - 在同一端口上运行 websocket 和 http 服务器(Rust、hyper)

c 指针数组

c++ - 存储对象列表

c - 如何创建类似 char *argv 的 char 指针

rust - 使用函数样式(flat_map等)实现递归迭代器的麻烦,该函数样式可处理错误并产生Result <…>类型的项

macros - 匹配下划线而不是宏中的标识

C++ 对象泄漏

将 C 数组和指针代码转换为 Go

regex - 在Rust中使用正则表达式查询MongoDB

rust - 如何在不释放缓冲区本身的情况下释放 Rust 在 FFI 缓冲区顶部分配的所有结构?