为什么从c_void指针的引用转换需要双重转换?

时间:2018-05-17 06:06:49

标签: casting rust ffi

使用外部函数接口(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)有关,但它并没有真正解释有关双重演员的任何内容。

1 个答案:

答案 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); }

Playground