【问题标题】:How to hold Rust objects in Rust code created through C++?如何在通过 C++ 创建的 Rust 代码中保存 Rust 对象?
【发布时间】:2020-06-12 06:39:57
【问题描述】:

我想通过 C++ 创建 Rust 结构的实例。 C++ 有 main 函数,Rust 代码用作库。

为了实现这一点,我需要一种将实例存储在某种列表中并将列表的索引返回给 C++ 的方法,这样它就可以像指向 Rust 结构的指针一样工作。

Rust 不支持静态成员,因此我无法创建 static rust_instances: std::vec::Vec = std::vec::Vec::new() 来保存 Rust 结构。

这里最好的选择是什么?

我已经搜索并找到了一些模拟静态元素的解决方法,但我想知道是否有更好的方法来解决这个问题。

【问题讨论】:

  • 你的 Rust 代码有 C 或 C++ 接口吗?如果是这样,你就不能这样称呼吗?
  • 在 Rust 内部也有像 lazy_static 这样的东西可以做这样的事情。
  • @tadman 我的 Rust 代码有一个 C 接口。但是如果我想在 Rust 上创建多个结构实例怎么办?我在哪里存放它们? main 函数在 C++ 端,所以 Rust 需要静态存储东西
  • 主要功能在 C++ 端,所以 Rust 需要静态存储东西 - 这对我来说毫无意义。为什么在 C++ 中使用 Rust 意味着您需要将内容存储在静态内存中,而不是使用堆栈和堆?

标签: rust


【解决方案1】:

为了实现这一点,我们需要一种方法将实例存储到某种列表中,并将列表的索引返回给 C++,因此它的工作方式类似于指向 Rust 结构的指针。

我不明白为什么会这样。您不需要静态列表来从 Rust 返回指针。只需在 Rust 中分配一个 Box 并将其返回给 C++ 代码——带有 T: SizedBox<T> 具有 the same memory layout as a C pointer

如链接文档中所述,您的代码可以简单地如下所示:

// C++ header

// Returns ownership to the caller
extern "C" void *foo_new();

// Borrows mutably. The pointee cannot be changed by a different thread
// during the runtime of the function. The argument must be a pointer
// allocated with foo_new().
extern "C" void foo_transmogrify(void *);

// Takes ownership from the caller; no-op when invoked with NULL
extern "C" void foo_delete(void *);
#[repr(C)]
pub struct Foo {
    glonk: bool,
}

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

#[no_mangle]
pub extern "C" fn foo_transmogrify(foo: &mut Foo) {
    foo.glonk = true;
}

#[no_mangle]
pub extern "C" fn foo_delete(_: Option<Box<Foo>>) {}

请注意,释放函数可以简单地为空。它将获得Box 的所有权并隐式将其放在函数体的末尾。

【讨论】:

  • 如果我理解正确的是阅读 rust 页面,在 C 端,我们将有一个指向 Rust 结构的 C 结构版本的指针,对吧?但是我的结构很复杂,我无法制作它的 C 版本。也许我可以制作一个包含指向原始结构的指针的结构?然后我可以在 C++ 和 Rust 中都有这个结构?
  • @LucasZanella 如果不能在C端表示,就用不透明的指针void*。您无法从 C 访问结构内的字段,但如果您无法在 C 中表示它,那么无论如何您都不能这样做。
  • 对不起,我没有理解。你的意思是void*在哪里?我之前使用过void* 返回类型,并在java 端转换为int64。您的意思是在 Rust 上返回 Box&lt;ComplicatedStruct&gt;,但在 C++ 端期望它是 void*?然后将这个void* 传递给Rust 并在Rust 上再次接收uint64 以调用它的方法?
  • @LucasZanella 在上面的 C++ sn-p 中,您可以将 Foo 替换为 void,它应该可以正常工作。在其他应该在 Rust 端运行 Foo 的函数中,您可以在 C++ 端使用 void *,在 Rust 端使用 &amp;Foo&amp;mut Foo
  • @LucasZanella 在 C 中,您可以使用不透明的结构(例如 struct foo;)而不是 void,它根本不会在任何地方完全定义,并且仅在指针后面使用。我将您推荐给FFI Omnibus(请注意,C 清单中的struct zip_code_database 未定义)。我很确定它在 C++ 中的工作方式相同,因为这也是 "PImpl" technique 的基础。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-07
  • 1970-01-01
  • 1970-01-01
  • 2017-04-25
  • 2021-05-11
相关资源
最近更新 更多