
现有项目由 rust 实现,现在希望将部分功能封装为 C 动态库,给其他语言使用。C 库 API 使用流程是这样的:
// 不透明指针,需要使用方持有 #define Ctx void *; // 第 1 步 初始化 Ctx,然后将指针传给使用方 int32_t ctx_open(Ctx *ctx); // 第 2 步 调用相关功能接口时,需要将 ctx 传 int32_t ctx_use(Ctx ctx); // 第 3 步 使用方用该方法来完成资源释放 int32_t ctx_close(Ctx ctx); 对 rust unsafe 部分不熟悉,在裸指针转换以及 Ctx 生命周期维护上卡住了。
我现在的代码大概是这样的
pub type Ptr = *mut ffi::c_void; #[no_mangle] pub extern "C" fn ctx_open(handle: *mut Ptr) -> i32 { let ctx: Box<Ctx> = Box::new(Ctx { }); let ptr = Box::<Ctx>::into_raw(ctx); let ptr = ptr as Ptr; unsafe {*handle = ptr}; 0 // 我希望 ctx 不会因为离开作用域而自动 drop,我不确定以上代码是否正确 } #[no_mangle] pub extern "C" fn ctx_use(handle: Ptr) -> i32 { // 这应该需要将 handle 转换为 Ctx 可可变借用(如果不是借用,可能会导致 Ctx 对象在这个函数结束就释放了),不知道怎么做 } #[no_mangle] pub extern "C" fn ctx_close<'a>(handle: Ptr)-> i32 { let mut ctx = unsafe { Box::<Ctx>::from_raw(handle as *mut Ctx)}; unsafe {drop(yy)}; 0 // 释放掉资源,不知道是否正确 } 1 bearice 2022-12-02 23:42:08 +08:00 1) The into_raw function consumes a box and returns the raw pointer. It doesn’t destroy T or deallocate any memory. 2) let ctx : &Ctx= unsafe { &*handle.cast() }; 3) 没错 |
2 sosilver 2022-12-02 23:47:28 +08:00 via Android rust 这边没必要用 void *,写个*mut T 还清楚些; 怎么获得引用?当然是 dereferencing ; 使用指针时注意判断 null |
3 sosilver 2022-12-03 00:22:42 +08:00 via Android 翻了下 wasmer 和 slint-ui 的 ffi ,*mut T, &mut T, Option<&mut T>, Option<Box<T>>啥都在用,也没什么检查,看来还是怎么方便怎么来 |
5 elden 2022-12-03 13:36:35 +08:00 可以试试 safer_ffi ,更容易 /安全地写 FFI 胶水代码。 |
6 cppc/a> 2022-12-04 13:09:10 +08:00 |