定义指向 C 不透明指针的字段的 Rust 习语是什么? [英] What's the Rust idiom to define a field pointing to a C opaque pointer?
问题描述
给定一个结构:
#[repr(C)]
pub struct User {
pub name: *const c_char,
pub age: u8,
pub ctx: ??,
}
字段 ctx
只能由 C 代码操作;它是一个指向 C 结构 UserAttr
的指针.
the field ctx
would only be manipulated by C code; it's a pointer to a C struct UserAttr
.
根据 Rust FFI 文档,选择将被定义为不透明类型 pub enum UserAttr {}
.但是,我发现 Rust 无法复制其值,例如为什么对象的地址会跨方法变化一>.
According to the Rust FFI documentation, the choice would be defined as an opaque type pub enum UserAttr {}
. However, I found that Rust is unable to copy its value, e.g. why does the address of an object change across methods.
在 Rust 中定义这样一个不透明指针的正确方法是什么,以便它的值(作为指针)在方法之间被复制?
What's the right way in Rust to define such an opaque pointer, so that its value (as a pointer) gets copied across methods?
推荐答案
未来
RFC 1861 引入了外部类型的概念.虽然已实施,但尚未稳定.一旦实现,它将成为首选实现:
The future
RFC 1861 introduced the concept of an extern type. While implemented, it is not yet stabilized. Once it is, it will become the preferred implementation:
#![feature(extern_types)]
extern "C" {
type Foo;
}
type FooPtr = *mut Foo;
今天
文档 状态:
为了在 Rust 中做到这一点,让我们创建我们自己的不透明类型:
To do this in Rust, let’s create our own opaque types:
#[repr(C)] pub struct Foo { private: [u8; 0] }
#[repr(C)] pub struct Bar { private: [u8; 0] }
extern "C" {
pub fn foo(arg: *mut Foo);
pub fn bar(arg: *mut Bar);
}
通过包含一个私有字段而没有构造函数,我们创建了一个不透明的我们无法在此模块之外实例化的类型.空数组既为零大小又与 #[repr(C)]
兼容.但是因为我们的Foo
和 Bar
类型不同,我们将在两者之间获得类型安全其中两个,所以我们不会意外地将指向 Foo
的指针传递给bar()
.
By including a private field and no constructor, we create an opaque
type that we can’t instantiate outside of this module. An empty array
is both zero-size and compatible with #[repr(C)]
. But because our
Foo
and Bar
types are different, we’ll get type safety between the
two of them, so we cannot accidentally pass a pointer to Foo
to
bar()
.
创建了一个不透明的指针,因此没有正常的方法来创建这样的类型;你只能创建指向它的指针.
An opaque pointer is created such that there's no normal way of creating such a type; you can only create pointers to it.
mod ffi {
use std::ptr;
pub struct MyTypeFromC { _private: [u8; 0] }
pub fn constructor() -> *mut MyTypeFromC {
ptr::null_mut()
}
pub fn something(_thing: *mut MyTypeFromC) {
println!("Doing a thing");
}
}
use ffi::*;
struct MyRustType {
score: u8,
the_c_thing: *mut MyTypeFromC,
}
impl MyRustType {
fn new() -> MyRustType {
MyRustType {
score: 42,
the_c_thing: constructor(),
}
}
fn something(&mut self) {
println!("My score is {}", self.score);
ffi::something(self.the_c_thing);
self.score += 1;
}
}
fn main() {
let mut my_thing = MyRustType::new();
my_thing.something();
}
稍微分解一下:
// opaque -----V~~~~~~~~~V
*mut MyTypeFromC
// ^~~^ ------------ pointer
因此它是一个不透明的指针.移动结构体 MyRustType
不会改变指针的值.
Thus it's an opaque pointer. Moving the struct MyRustType
will not change the value of the pointer.
此答案的先前迭代和文档建议使用空枚举 (enum MyTypeFromC {}
).没有变体的枚举在语义上等同于 never 类型 (!
),后者是一种不存在的类型.有人担心使用这种构造可能会导致未定义的行为,因此移动到空数组被认为更安全.
Previous iterations of this answer and the documentation suggested using an empty enum (enum MyTypeFromC {}
). An enum with no variants is semantically equivalent to the never type (!
), which is a type that cannot exist. There were concerns that using such a construct could lead to undefined behavior, so moving to an empty array was deemed safer.
这篇关于定义指向 C 不透明指针的字段的 Rust 习语是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!