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]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值