我正在努力将结构传递给FFI,FFI接受void并在另一端读回来.
有问题的库是libtsm,一个终端状态机.它允许您输入输入,然后找出输入后终端的状态.
它将draw函数声明为:
pub fn tsm_screen_draw(con: *tsm_screen, draw_cb: tsm_screen_draw_cb, data: *mut c_void) -> tsm_age_t;
Run Code Online (Sandbox Code Playgroud)
其中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
);
Run Code Online (Sandbox Code Playgroud)
这里重要的部分是data参数.它允许用户通过指向自我实现状态的指针,对其进行操作并在绘制后使用它.给出一个简单的结构:
struct State {
state: int
}
Run Code Online (Sandbox Code Playgroud)
我该怎么做呢?我不确定如何正确地将指向结构的指针转换为void和back.
Vla*_*eev 22
您不能将结构转换为c_void,但您可以使用某些指针强制类型转换结构的引用*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);
Run Code Online (Sandbox Code Playgroud)
也可以使用std::mem::transmute()函数在指针之间进行转换,但它是比这里真正需要的更强大的工具,应尽可能避免使用.
请注意,您必须格外小心地将不安全的指针转换回引用.如果tsm_screen_draw在另一个线程中调用其回调或将其存储在全局变量中然后另一个函数调用它,那么state在调用回调时局部变量可能会超出范围,这会使程序崩溃.
| 归档时间: |
|
| 查看次数: |
12566 次 |
| 最近记录: |