定义指向 C 不透明指针的字段的 Rust 习语是什么? [英] What's the Rust idiom to define a field pointing to a C opaque pointer?

查看:33
本文介绍了定义指向 C 不透明指针的字段的 Rust 习语是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给定一个结构:

#[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)] 兼容.但是因为我们的FooBar 类型不同,我们将在两者之间获得类型安全其中两个,所以我们不会意外地将指向 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆