【问题标题】:Working with c_void in an FFI在 FFI 中使用 c_void
【发布时间】:2014-06-12 18:15:38
【问题描述】:

我正在努力通过一个接受 void 的 FFI 传递一个结构并在另一端读回它。

有问题的库是 libtsm,一个终端状态机。它允许您输入输入,然后找出终端在输入之后的状态。

它把它的draw函数声明为:

pub fn tsm_screen_draw(con: *tsm_screen, draw_cb: tsm_screen_draw_cb, data: *mut c_void) -> tsm_age_t;

其中 tsm_screen_draw_cb 是由库用户实现的回调,带有签名:

pub type tsm_screen_draw_cb = extern "C" fn(
  con: *tsm_screen,
  id: u32,
  ch: *const uint32_t,
  len: size_t,
  width: uint,
  posx: uint,
  posy: uint,
  attr: *tsm_screen_attr,
  age: tsm_age_t,
  data: *mut c_void
);

这里的重要部分是data 参数。它允许用户通过一个指向自我实现状态的指针,在绘制后对其进行操作和使用。给定一个简单的结构:

struct State {
  state: int
}

我该如何正确地做到这一点?我不确定如何正确地将指向结构的指针转换为 void 并返回。

【问题讨论】:

    标签: ffi rust


    【解决方案1】:

    您不能将 struct 转换为 c_void,但您可以将结构的 reference 转换为 *mut c_void 并使用一些指针转换返回:

    fn my_callback(con: *tsm_screen, ..., data: *mut c_void) {
        // unsafe is needed because we dereference a raw pointer here
        let data: &mut State = unsafe { &mut *(data as *mut State) };
        println!("state: {}", data.state);
        state.x = 10;
    }
    
    // ...
    
    let mut state = State { state: 20 };
    let state_ptr: *mut c_void = &mut state as *mut _ as *mut c_void;
    tsm_screen_draw(con, my_callback, state_ptr);
    

    也可以使用std::mem::transmute() 函数在指针之间进行强制转换,但它比这里真正需要的要强大得多,应尽可能避免使用。

    请注意,将不安全的指针转换回引用时必须格外小心。如果tsm_screen_draw在另一个线程中调用它的回调或将其存储在一个全局变量中,然后另一个函数调用它,那么state局部变量很可能在回调被调用时超出范围,这会导致你的程序崩溃。

    【讨论】:

    • 我建议避免使用transmute:它非常强大,很容易不小心转换错误的东西。您可以使用as 直接处理指针,例如let data = &mut *(data as *mut State);let state_ptr = &mut state as *mut _ as *mut c_void;。 (特别是写&mut *...,因为这保证你正在处理一个指针,不像transmute。)
    • @dbaupp,我确信将指向不同类型的指针相互转换是不可能的。谢谢指正。
    • 嗯,这比我已经走得更远了,但是当我尝试访问数据成员时,这对我来说是段错误。
    • @Skade,state 很可能已经超出范围并被销毁。仔细检查您的回调是否仅在 state 仍然存在时才被调用。
    • 嗯,不知道为什么会这样,通话后直接使用。 FWIW,我把代码放在这里:github.com/skade/rust-terminal/blob/master/src/main.rs。它应该(tm)使用简单的“make lib && make exe”构建,使用“cat test/reference_input | make run”运行它。
    猜你喜欢
    • 1970-01-01
    • 2020-08-24
    • 2017-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-03
    • 2018-08-29
    • 1970-01-01
    相关资源
    最近更新 更多