【问题标题】:What's the Rust idiom to define a field pointing to a C opaque pointer?定义指向 C 不透明指针的字段的 Rust 习惯用法是什么?
【发布时间】:2016-11-13 21:34:21
【问题描述】:

给定一个结构:

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

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

根据the Rust FFI documentation,选择将被定义为不透明类型pub enum UserAttr {}。但是,我发现 Rust 无法复制它的值,例如why does the address of an object change across methods.

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

【问题讨论】:

  • 并不是说“Rust 无法复制它的值”,只是这就是 Rust 和 C 等语言的工作原理。您是否阅读了另一个问题的答案,特别是关于 Box 的答案?

标签: rust


【解决方案1】:

未来

RFC 1861 引入了外部类型的概念。在实施时,它还没有稳定下来。一旦实现,它将成为首选实现:

#![feature(extern_types)]

extern "C" {
    type Foo;
}

type FooPtr = *mut Foo;

今天

The documentation 状态:

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

#[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().

创建了一个不透明的指针,因此没有正常的方法来创建这种类型;你只能创建指向它的指针。

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 不会改变指针的值。

过去

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-18
    • 1970-01-01
    • 2021-12-09
    • 2011-03-16
    • 2023-02-23
    • 1970-01-01
    相关资源
    最近更新 更多