在使用外部函数接口 (FFI) 时,我经常看到从引用到指针到结构到指针到指针到无效的双重转换。例如,给定一个类似 FFI 的函数:
unsafe fn ffi(param: *mut *mut c_void) {}
Run Code Online (Sandbox Code Playgroud)
调用方法是:
struct foo;
let mut bar: *mut foo = ptr::null_mut();
unsafe { ffi(&mut bar as *mut *mut _ as *mut *mut c_void); }
Run Code Online (Sandbox Code Playgroud)
删除中间转换会产生此错误:
unsafe fn ffi(param: *mut *mut c_void) {}
Run Code Online (Sandbox Code Playgroud)
我试图让编译器通过强制转换为明显错误的类型来告诉我中间类型是什么:
let mut bar: *mut foo = ptr::null_mut();
let mut test: u8 = &mut bar as *mut *mut _;
Run Code Online (Sandbox Code Playgroud)
这导致了这个错误:
struct foo;
let mut bar: *mut foo = ptr::null_mut();
unsafe { ffi(&mut bar as *mut *mut _ as *mut *mut c_void); }
Run Code Online (Sandbox Code Playgroud)
但*-ptr似乎不是我可以代替的实际类型_。为什么as *mut *mut _需要中间体,推断类型是什么?
我发现这个问题是相关的(在 FFI 中使用 c_void),但它实际上并没有解释关于双重转换的任何事情。
如果你有:
let mut bar: *mut foo = ptr::null_mut();
Run Code Online (Sandbox Code Playgroud)
然后你拿&mut bar,类型是&mut *mut foo。但是您需要*mut *mut foo,因此您可以简单地通过执行&mut *mut foo as *mut *mut _,_推断为foo(尝试明确键入它:)来强制它*mut *mut foo。一旦你把它作为一个原始指针,那么你就可以转换为*mut *mut c_void.
所以回顾一下,双重转换是必要的,首先从引用强制转换为原始指针,然后从原始指针强制转换为 a 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); }
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3321 次 |
| 最近记录: |