使用外部函数接口(FFI)时,我经常会看到从reference-to-pointer-to-struct到指针指向void的双重转换。例如,给定类似FFI的函数:
unsafe fn ffi(param: *mut *mut c_void) {}
调用它的方法是:
struct foo;
let mut bar: *mut foo = ptr::null_mut();
unsafe { ffi(&mut bar as *mut *mut _ as *mut *mut c_void); }
删除中间转换产生此错误:
error[E0606]: casting `&mut *mut foo` as `*mut *mut winapi::ctypes::c_void` is invalid
--> src\main.rs:36:18
|
36 | unsafe { ffi(&mut bar as *mut *mut c_void); }
|
我试图让编译器告诉我中间类型是什么,迫使它成为一个明显错误的类型:
let mut bar: *mut foo = ptr::null_mut();
let mut test: u8 = &mut bar as *mut *mut _;
导致此错误:
error[E0308]: mismatched types
--> src\main.rs:36:24
|
36 | let mut test: u8 = &mut bar as *mut *mut _;
| ^^^^^^^^^^^^^^^^^^^^^^^ expected u8, found *-ptr
|
= note: expected type `u8`
found type `*mut *mut _`
但*-ptr
似乎不是我可以代替_
的实际类型。为什么需要中间as *mut *mut _
,推断类型是什么?
我发现这个问题与(Working with c_void in an FFI)有关,但它并没有真正解释有关双重演员的任何内容。
答案 0 :(得分:2)
如果你有:
let mut bar: *mut foo = ptr::null_mut();
然后你选择&mut bar
,类型为&mut *mut foo
。但是您需要*mut *mut foo
,因此您只需执行&mut *mut foo as *mut *mut _
即可强制执行此操作,其中_
被推断为foo
(请尝试明确键入:*mut *mut foo
)。将它作为原始指针后,然后就可以转换为*mut *mut c_void
。
所以回顾一下,双重强制转换是必须首先强制从对原始指针的引用,然后从原始指针强制转换为c_void
,因为否则通常可以&# 39; t直接从引用转换为原始c_void
指针。
完全输入的示例:
let mut bar: *mut foo = std::ptr::null_mut();
let mut_ref: &mut *mut foo = &mut bar;
let raw_ptr: *mut *mut foo = mut_ref as *mut *mut _;
let void_cast: *mut *mut c_void = raw_ptr as *mut *mut c_void;
unsafe { ffi(void_cast); }