定义指向 C 不透明指针的字段的 Rust 习语是什么?



给定一个结构:

#[repr(C)]
pub struct User {
    pub name: *const c_char,
    pub age: u8,
    pub ctx: ??,
}

字段ctx只能由 C 代码操作;它是指向 C 结构UserAttr的指针。

根据 Rust FFI 文档,该选择将被定义为不透明类型 pub enum UserAttr {} 。但是,我发现 Rust 无法复制其值,例如为什么对象的地址会跨方法更改。

在 Rust 中定义这样一个不透明的指针的正确方法是什么,以便它的值(作为指针)跨方法复制?

未来

RFC 1861 引入了外部类型的概念。虽然已实施,但尚未稳定下来。一旦成为,它将成为首选实现:

#![feature(extern_types)]
extern "C" {
    type Foo;
}
type FooPtr = *mut Foo;

今天

Rustonomicon指出:

要在 Rust 中做到这一点,让我们创建我们自己的不透明类型:

#[repr(C)]
pub struct Foo {
    _data: [u8; 0],
    _marker:
        core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
}
#[repr(C)]
pub struct Bar {
    _data: [u8; 0],
    _marker:
        core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
}

通过包含至少一个私有字段和不构造函数,我们创建了一个不透明类型,我们无法在此模块之外实例化。(没有字段的结构可以由任何人实例化。我们也想在 FFI 中使用这种类型,所以我们必须添加 #[repr(C)] .标记确保编译器不会将结构标记为SendSyncUnpin不应用于结构。(*mut u8不是SendSyncPhantomPinned不是Unpin

创建不透明指针时,没有创建此类类型的正常方法;只能创建指向它的指针。

mod ffi {
    use std::ptr;
    pub struct MyTypeFromC {
        _data: [u8; 0],
        _marker:
            core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
    }
    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不会更改指针的值。

往事

此答案和文档的先前迭代建议使用空枚举 ( enum MyTypeFromC {} )。没有变体的枚举在语义上等价于永不类型(!),后者是不可能存在的类型。有人担心使用这样的结构可能会导致未定义的行为,因此移动到空数组被认为更安全。

最新更新