Rust 具有表示非NULL
指针的ptr::NonNull
类型。在 FFI 中使用此类型是否安全?
它是否保证具有相同的二进制表示(忽略非 FFI 上下文,例如Option
优化(、对齐、寄存器使用作为*mut T
?
例如,我可以实现此接口吗:
void call_me_from_c(char *without_nulls) __attribute__((nonnull));
跟
extern "C" fn call_me_from_c(without_nulls: ptr::NonNull<c_char>)
我不希望这能做任何事情(除了在与NULL
;)滥用时导致 UB,但我希望接口记录该函数需要非NULL
参数。
这取决于你编译的 Rust 版本。
锈 1.29 及以上
NonNull
现在有repr(transparent)
,所以只要包装类型是安全的,就可以安全地在 FFI 中使用。
#[stable(feature = "nonnull", since = "1.25.0")]
#[repr(transparent)]
pub struct NonNull<T: ?Sized> {
pointer: NonZero<*const T>,
}
生锈之前 1.29
我不会用它来做这样。主要原因是由于其定义:
#[stable(feature = "nonnull", since = "1.25.0")]
pub struct NonNull<T: ?Sized> {
pointer: NonZero<*const T>,
}
更具体地说,我关心的是定义中没有的内容:#[repr(transparent)]
(强调我的(:
具有此表示形式的结构与单个非零大小字段具有相同的布局和 ABI。
由于将 newtype 放入由 repr(transparent)
解决的 FFI 函数中,我遇到了错误编译,所以这不仅仅是一项学术练习。