This question already has an answer here:
Why would it be necessary to perform two casts to a mutable raw pointer in a row?

(1个答案)


2年前关闭。




在使用外来功能接口(interface)(FFI)时,我经常看到从引用到指针到结构到指针到指针到无效的双重转换。例如,给定类似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)相关的问题,但实际上并没有解释有关双重转换的任何信息。

最佳答案

如果你有:

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,因为否则您通常无法直接从引用转换为原始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

关于casting - 为什么从引用到c_void指针的转换需要双重转换?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50384395/

10-12 02:31