代码之家  ›  专栏  ›  技术社区  ›  ItsTimmy

使用C回调用户数据存储盒装铁锈封口时的分段错误

  •  1
  • ItsTimmy  · 技术社区  · 7 年前

    this answer

    Test::trigger_callback(...)

    extern crate libc;
    
    use libc::c_void;
    use std::mem::transmute;
    
    struct Test {
        callback: extern "C" fn(data: i32, user: *mut c_void) -> (),
        userdata: *mut c_void,
    }
    
    extern "C" fn c_callback(data: i32, user: *mut libc::c_void) {
        unsafe {
            println!("Line {}. Ptr: {}", line!(), user as u64);
            let func: &mut Box<FnMut(i32) -> ()> = transmute(user);
            println!("Line {}. Data: {:?}", line!(), data);
            (*func)(data);
            println!("Line {}", line!());
        }
    }
    
    impl Test {
        fn new<F>(func: F) -> Test
        where
            F: FnMut(i32) -> (),
            F: 'static,
        {
            let func = Box::into_raw(Box::new(Box::new(func)));
            println!("Line: {}, Ptr: {}", line!(), func as u64);
    
            Test {
                callback: c_callback,
                userdata: func as *mut c_void,
            }
        }
    
        fn trigger_callback(&self, data: i32) {
            (self.callback)(data, self.userdata);
        }
    }
    
    fn main() {
        let test = Test::new(|data: i32| {
            println!("Inside callback! Data: {}", data);
        });
    
        test.trigger_callback(12345);
    }
    

    如链接答案所述, Box 盒子

    运行时,此代码打印出来:

    Line: 29, Ptr: 140589704282120
    Line 13. Ptr: 140589704282120
    Line 15. Data: 12345
    Segmentation fault (core dumped)
    

    extern "C"

    为什么?据我所知,在 然后使用 Box::into_raw(...)

    1 回复  |  直到 7 年前
        1
  •  1
  •   Shepmaster Tim Diekmann    7 年前
    Box::into_raw(Box::new(Box::new(func)));
    

       = note: expected type `()`
                  found type `*mut std::boxed::Box<F>`
    

    let func: &mut Box<FnMut(i32) -> ()> = transmute(user);
    

    // Trait object with a stable address
    let func = Box::new(func) as Box<FnMut(i32)>;
    // Thin pointer
    let func = Box::new(func);
    // Raw pointer
    let func = Box::into_raw(func);
    

    Box<FnMut(i32) -> ()>
    

    返回类型 () Box<FnMut(i32)>

    让func:&mut box<fnmut(i32)->()>=transmute(用户);
    

    很难避免 transmute

    extern "C" fn c_callback(data: i32, user: *mut libc::c_void) {
        let user = user as *mut Box<FnMut(i32)>;
        unsafe {
            (*user)(data);
        }
    }
    

    类型别名

    type CallbackFn = Box<FnMut(i32)>;
    
    let user = user as *mut CallbackFn;
    
    let func = Box::new(func) as CallbackFn;
    

    另请参见:

    推荐文章