我想为我的 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
。
另见:
- What's the Rust idiom to define a field pointing to a C opaque pointer?
- Why can comparing two seemingly equal pointers with == return false?
- How do I pass a closure through raw pointers as an argument to a C function?
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/