【问题标题】:Why does casting from a reference to a c_void pointer require a double cast? [duplicate]为什么从对 c_void 指针的引用进行强制转换需要双重强制转换? [复制]
【发布时间】:2018-05-17 06:06:48
【问题描述】:

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

【问题讨论】:

  • 哇,我都回答了​​,完全忘记了,很好。我确实像以前一样有这种模糊的感觉。
  • 我很欣赏这两个答案:)

标签: casting rust ffi


【解决方案1】:

如果你有:

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

【讨论】:

  • 要抛弃外部引用,不需要指定内部指针类型; mut_ref as *mut _ as *mut *mut c_void 会起作用。
  • 是的,尽可能明确,因为 OP 在跟踪类型时遇到了问题。
猜你喜欢
  • 2021-05-08
  • 1970-01-01
  • 2013-06-03
  • 2015-01-29
  • 1970-01-01
  • 2012-04-12
  • 2021-03-19
  • 1970-01-01
相关资源
最近更新 更多