我有一个Option<&T>
我想要一个原始的*const T
如果选项为 None
则为 null 。我想包装一个 FFI 调用,该调用采用指向 Rust 分配的对象的指针。
此外,我正在使用的 FFI 接口(interface)具有借用语义(我分配某些内容并传入指向它的指针),而不是所有权语义
extern "C" {
// Parameter may be null
fn ffi_call(*const T);
}
fn safe_wrapper(opt: Option<&T>) {
let ptr: *const T = ???;
unsafe { ffi_call(ptr) }
}
我可以使用 match
声明来执行此操作,但该方法感觉非常冗长。
let ptr = match opt {
Some(inner) => inner as *const T,
None => null(),
};
我还可以将引用映射到指针,然后使用 unwrap_or
.
let ptr = opt.map(|inner| inner as *const T).unwrap_or(null());
但是,我担心指针在通过闭包时可能会失效。 Rust 是否保证最终指针将指向与原始引用相同的东西?如果T
是 Copy
,这是否以有意义的方式改变了语义?有没有更好的方法让我忽略?
最佳答案
是的,这是安全的。我会把它写成:
use std::ptr;
fn safe_wrapper(opt: Option<&u8>) {
let p = opt.map_or_else(ptr::null, |x| x);
unsafe { ffi_call(p) }
}
如果您发现自己写了很多这样的内容,您可以将其变成一个特征并将其减少为单个方法调用。
the pointer might be invalidated as it passes through the closure
如果您自己以某种方式使其无效,则可能会这样。因为该函数采用引用,所以您可以确定引用的值在函数调用期间有效 - 这就是 Rust 借用检查器的目的。
指针变得无效的唯一方法是更改指针的值(例如,向其添加偏移量)。既然你不这样做,那就没问题。
Does Rust make a guarantee that the final pointer will point to the same thing as the original reference?
这取决于你所说的“最终”是什么意思。将引用转换为指针将始终导致两个值包含内存中的相同位置。其他任何东西都可能是故意恶意的,而且一开始就没有人会使用 Rust。
If
T
isCopy
, does this change the semantics in a meaningful way?
没有。此外,我们正在谈论 &T
,即 始终 复制
另请参阅:
- Convert Option<&mut T> to *mut T
- Should we use Option or ptr::null to represent a null pointer in Rust?
- Is it valid to use ptr::NonNull in FFI?
the FFI interface I am using has borrowing semantics (I allocate something and pass in a pointer to it), not ownership semantics
需要明确的是,您不能纯粹根据函数类型来确定所有权。
此 C 函数取得所有权:
void string_free(char *)
此 C 函数借用:
size_t string_len(char *)
两者都采用指针。 Rust 通过明确界定什么是借用和什么是所有权转移来改善这种情况。
extern "C" { // Parameter may be null fn ffi_call(*const T); }
这段代码毫无意义;它没有定义泛型类型 T
并且 FFI 函数无论如何也不能具有泛型类型。
关于rust - 使用闭包从 Option<&T> 获取原始指针是否安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55320663/