Rust : *mut c_void 转型 &‘a mut dyn T

说明一下,下面引用的文章值得好好学习。

https://iandouglasscott.com/2018/05/28/exploring-rust-fat-pointers/

https://users.rust-lang.org/t/why-cant-a-convert-a-mut-c-void-into-mut-dyn-std-read/95780/2

首先要用到libc库;

libc = "0.2"

c_void是libc中的类型。

一、*mut c_void -> &'a mut dyt T

方案一:

use libc::{c_int, c_void};
trait T{
}
unsafe fn unwrap_T<'a>(spi: *mut c_void) -> &'a mut dyn T {
    &mut **(spi as *mut *mut dyn T) // 两个解引用符号
}

这样也是可以的:即多加一个&mut或mut.; 当然后面第二行也需要多加一个""解引用符号。这个本质就是让as的两者对象大小一致就行。

unsafe fn unwrap_t<'a>(spi: *mut c_void) -> &'a mut dyn T {
    let a = spi as *mut  &mut &mut dyn T; 
    &mut *** a  //增加了一个解引用符号*,三个解引用符号

}

方案二:

是否可以?

unsafe fn unwrap_T<'a>(spi: *mut c_void) -> &'a mut dyn T {
     std::mem::transmute::<*mut c_void, &'a mut dyn T>(spi)
}

发现会报错。提示指针指向的类型的大小不一样。前者是占8个字节,后者占16个字节;
&'a mut dyn T 是一个胖指针(具体看上面参考资料,一个指向data,一个指向vtable),而 *mut c_void是一个瘦指针。


fn main(){
    let s = std::mem::size_of::<*mut c_void>();
    println!("size of s :{s}");
    let t = std::mem::size_of::<& mut dyn T>();
    println!("size of t :{t}");
    let mm =  std::mem::size_of::<*mut &mut dyn T>(); // std::mem::size_of::<*mut *mut dyn T>()
    println!("size of mm :{mm}");
}

output:

size of s :8
size of t :16
size of mm :8

可见,两者size不一样,不能简单transmute。

改一下可以:

unsafe fn unwrap_T<'a>(spi: *mut c_void) -> &'a mut dyn T {
     let _spi = std::mem::transmute::<*mut c_void, &'a mut *mut dyn T>(spi); // 方案2
    &mut **_spi  //2个解引用
}

从语法上看,也可以:

unsafe fn unwrap_Ti<'a>(spi: *mut c_void) -> &'a mut dyn QuoteSpi {
     let _spi = std::mem::transmute::<*mut c_void, &'a mut *mut  *mut  dyn T>(spi); // 方案3 多了一个*mut
    &mut ***_spi  // 3个解引用
}

二、其它

1、Box<Box< dyn QuoteSpi>> -> *mut Box< dyn QuoteSpi> -> *mut c_void

2、Box::into_raw(Box::new(quote_spi_stub)) -> *mut XTP_API_QuoteSpi)

    pub fn register_spi<T: QuoteSpi>(&mut self, spi: T) {
        let trait_object_box: Box<Box<dyn QuoteSpi>> = Box::new(Box::new(spi));
        let trait_object_pointer =
            Box::into_raw(trait_object_box) as *mut Box<dyn QuoteSpi> as *mut c_void;

        let quote_spi_stub = unsafe { QuoteSpiStub::new(trait_object_pointer) };

        let ptr = Box::into_raw(Box::new(quote_spi_stub));
        self.quote_spi_stub = Some(ptr);
        unsafe { QuoteApi_RegisterSpi(self.quote_api, ptr as *mut XTP_API_QuoteSpi) };
    }

3、 pub unsafe fn from_raw(raw: *mut T) -> Box

let x = Box::new(5);
let ptr = Box::into_raw(x);
let x = unsafe { Box::from_raw(ptr) };

4、into_raw(b: Box < T > ) -> *mut T

let x = Box::new(String::from("Hello"));
let ptr = Box::into_raw(x);
let x = unsafe { Box::from_raw(ptr) };

5、参考

fn ffi_reading_stuff<R: io::Read>(reader: &mut R) {
    // Convert the trait into a raw pointer of a `dyn io::Read` object.
    let boxed_reader: Box<&mut dyn io::Read> = Box::new(reader);
    let reader_ptr: *mut &mut dyn io::Read = Box::into_raw(boxed_reader);

    // Conver the pointer into a `ffi::c_void` pointer so that we can pass it into an FFI function.
    let void_ptr: *mut ffi::c_void = reader_ptr as *mut ffi::c_void;
    /// Do FFI stuff here...
    // Receive the pointer back from FFI, and cast it back into the `dyn io::Read` object so that we can work with it properly.
    //
    // Alas this fails because "`c_void: std::io::Read` is not satisfied", but why?
    let returned_reader_ptr: Box<&mut dyn io::Read> = unsafe {
        Box::from_raw(void_ptr as *mut &mut dyn io::Read)
    };
    
    // Use the pointer, so Miri will check if we did everything right
    let _ = returned_reader_ptr.read(&mut [0u8]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 C 语言中是无法直接传递闭包的,但是可以通过使用函数指针来模拟闭包的行为。在 Rust 中,可以使用 `extern "C"` 修饰符将 Rust 函数导出为 C 函数,然后将其作为参数传递给 C 函数。 下面是一个使用原始指针传递闭包作为 C 函数参数的示例代码: ```rust // 定义一个闭包类型 type Callback = Box<dyn FnMut()>; // 将闭包转换为原始指针 fn callback_to_ptr(callback: Callback) -> *mut std::ffi::c_void { Box::into_raw(callback) as *mut std::ffi::c_void } // 将原始指针转换为闭包 unsafe fn ptr_to_callback(ptr: *mut std::ffi::c_void) -> Callback { Box::from_raw(ptr as *mut dyn FnMut()) } // C 函数,接受一个指向闭包的原始指针作为参数 extern "C" fn call_closure(ptr: *mut std::ffi::c_void) { unsafe { // 将原始指针转换为闭包 let mut callback = ptr_to_callback(ptr); // 调用闭包 callback(); // 将闭包转换回原始指针,以防止其被 Rust 的垃圾回收器释放 callback = callback_to_ptr(callback); } } fn main() { // 定义一个闭包 let mut closure = || { println!("Hello from closure!"); }; // 将闭包转换为原始指针 let ptr = callback_to_ptr(Box::new(closure)); // 调用 C 函数,并传递闭包的原始指针作为参数 unsafe { call_closure(ptr); } } ``` 在上面的示例代码中,我们首先定义了一个闭包类型 `Callback`,然后分别实现了将闭包转换为原始指针和将原始指针转换为闭包的函数。接下来,我们定义了一个 C 函数 `call_closure`,它接受一个指向闭包的原始指针作为参数。在 `main` 函数中,我们定义了一个闭包,并将其转换为原始指针。然后,我们调用了 C 函数 `call_closure`,并将闭包的原始指针作为参数传递给它。在 `call_closure` 函数中,我们将原始指针转换为闭包,并调用了它。 需要注意的是,在将闭包转换为原始指针时,我们使用了 `Box::into_raw` 函数。这个函数会将 `Box` 类型的对象转换为指向堆内存的原始指针,并释放 `Box` 对象的所有权。在将原始指针转换为闭包时,我们使用了 `Box::from_raw` 函数。这个函数会将指向堆内存的原始指针转换为 `Box` 类型的对象,并获取 `Box` 对象的所有权。需要注意的是,在使用 `Box::from_raw` 函数时,必须确保传递的指针是由 `Box::into_raw` 函数产生的。否则,可能会导致内存安全问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值