现有项目由 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 2022-12-04 13:09:10 +08:00
|