casting - 为什么从对 c_void 指针的引用进行强制转换需要双重强制转换?

标签 casting rust ffi

<分区>

在使用外部函数接口(interface) (FFI) 时,我经常看到从引用到指针到结构到指针到指针到 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 ) 但它实际上并没有解释任何关于双重 Actor 的事情。

最佳答案

如果你有:

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/

相关文章:

enums - 为枚举泛化一个函数

Haskell FFI 对具有可变参数的函数的支持

python - python如何将任意对象转换为列表?

c - c 中这两种转换格式 (void **) &a 和 (void *)a 的区别

arrays - 自动将 Vec 转换为数组

rust - 如何使用 remove 方法扩展基于枚举的多类型容器?

io - 读取文件时检测 EndOfFile IoResult

c++ - 将指针转换为 uint64_t

rust - 无法在不导致非法指令的情况下传递新类型包装的不安全 C 结构

winapi - Rust 编译期间的链接错误(Cargo)