我正在用Rust编写一个具有C接口的库.C方必须能够创建和销毁Rust 的物体(C方拥有并控制它们的生命周期 ).

我成功地将一个对象"泄漏"到C,但我不确定如何正确地释放它:

pub extern "C" fn create() -> *mut Foo {
   let obj = Foo; // oops, a bug
   let ptr = std::mem::transmute(&mut obj); // bad 
   std::mem::forget(obj); // not needed
   return ptr;
}

pub extern "C" fn destroy(handle: *mut Foo) {
   // get Foo back and Drop it??? 
}

我不确定如何将指针转回一个Rust 会使其脱落的对象.简单地取消引用*handle不会编译.

推荐答案

要向C发送Rust 对象,请执行以下操作:

#[no_mangle]
pub extern "C" fn create_foo() -> *mut Foo {
    Box::into_raw(Box::new(Foo))
}

或者利用Box是FFI安全的,与指针相同,而且只要ABI相同,Rust函数定义就不必与C头完全匹配:

#[no_mangle]
pub extern "C" fn create_foo() -> Box<Foo> {
   Box::new(Foo)
}

(返回Option<Box<Foo>>也可以,返回Result也可以.)

要从C借钱(但不是免费的):

#[no_mangle]
pub unsafe extern "C" fn peek_at(foo: *mut Foo) {
    let foo = foo.as_ref().unwrap(); // That's ptr::as_ref
}

或者利用参考资料和Option家 foreign 金融机构的安全性:

#[no_mangle]
pub extern "C" fn peek_at(foo: Option<&mut Foo>) {
    let foo = foo.unwrap();
}

接管/销毁之前交给C的Rust 物体:

#[no_mangle]
pub unsafe extern "C" fn free_foo(foo: *mut Foo) {
    assert!(!foo.is_null());
    Box::from_raw(foo); // Rust auto-drops it
}

或者使用Option<Box>是FFI安全的,并且由Rust管理的内存:

#[no_mangle]
pub unsafe extern "C" fn free_foo(foo: Option<Box<Foo>>) {
   // dropped implicitly
}

Rust相关问答推荐

为什么函数不接受选项T参数的所有权?

Rust:跨多个线程使用hashmap Arc和rwlock

用 rust 蚀中的future 展望 struct 的future

如何在递归数据 struct 中移动所有权时变异引用?

为什么AsyncRead在Box上的实现有一个Unpin特征绑定?

为什么我必须使用 PhantomData?在这种情况下它在做什么?

Rust 如何返回大类型(优化前)?

为什么是&mut发送?线程如何在安全的 Rust 中捕获 &mut?

需要一个有序向量来进行 struct 初始化

在1.5n次比较中找到整数向量中的最大和次大整数

`tokio::pin` 如何改变变量的类型?

由特征键控的不同 struct 的集合

如何在 Rust 中将 UTF-8 十六进制值转换为 char?

SDL2 没有在终端键上触发?

为什么我可以同时传递可变和不可变引用?

Rust 中的let是做什么的?

字符串切片的向量超出范围但原始字符串仍然存在,为什么判断器说有错误?

为什么我不能为 Display+Debug 的泛型类型实现 std::error::Error 但有一个不是泛型参数的类型?

如何将 u8 切片复制到 u32 切片中?

如何在 Rust 中构建一个 str