You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从Box<dyn Trait>中获取虚表指针?

Rust 中 dyn Trait 虚表的正确获取与访问方法

你的问题核心是错误地直接对 dyn Trait 指针做字节偏移来提取虚表指针,Rust 的胖指针(*mut dyn Trait)内存布局是两个连续的 usize,但不能直接通过指针偏移来访问第二个字段,正确的做法是将胖指针转换为对应布局的结构体来解析。

正确实现代码

#![feature(pointer_byte_offsets)]

trait MyRule {
    fn some_method1(&self) {}
    fn some_method2(&self) {}
}

struct MyData {
    data: u32,
}

impl MyRule for MyData {}

// 定义与 Rust 胖指针内存布局一致的结构体
#[repr(C)]
struct FatPtr {
    data_ptr: *mut (),
    vtable_ptr: *mut VTable,
}

// 定义虚表的内存布局(rustc 实际实现中的固定结构)
#[repr(C)]
struct VTable {
    destructor: unsafe fn(*mut ()),
    type_size: usize,
    type_align: usize,
    // 按 trait 中方法声明顺序排列的函数指针
    some_method1: unsafe fn(*const ()),
    some_method2: unsafe fn(*const ()),
}

fn main() {
    unsafe {
        let b: Box<dyn MyRule> = Box::new(MyData { data: 5 });
        let fat_ptr = Box::into_raw(b);

        // 将 dyn 指针强制转换为我们定义的 FatPtr 结构体,正确拆分数据指针和虚表指针
        let fat_ptr_struct = &*(fat_ptr as *const FatPtr);
        let data_ptr = fat_ptr_struct.data_ptr as *mut u32;
        dbg!(*data_ptr); // 输出: [src/main.rs:28] *data_ptr = 5

        // 访问虚表中的字段
        let vtable = &*fat_ptr_struct.vtable_ptr;
        dbg!(vtable.type_size); // 输出 MyData 的大小: 4
        dbg!(vtable.type_align); // 输出 MyData 的对齐值: 4

        // 调用虚表中的 trait 方法
        (vtable.some_method1)(data_ptr as *const ());
    }
}

关键说明

  1. 胖指针的正确解析:
    Rust 中 dyn Trait 对应的胖指针在内存中是两个连续的 usize:第一个指向数据,第二个指向虚表。通过 #[repr(C)] 定义的 FatPtr 结构体可以保证内存布局和胖指针完全一致,从而安全地拆分出两个指针。

  2. 虚表的布局规则:
    rustc 实现的虚表固定包含以下字段(顺序不可变):

    • 第一个字段:析构函数指针(用于清理 dyn 类型实例)
    • 第二个字段:类型的大小(对应 std::mem::size_of::<MyData>())
    • 第三个字段:类型的对齐值(对应 std::mem::align_of::<MyData>())
    • 后续字段:按 trait 中方法声明的顺序排列的函数指针
  3. 注意事项:
    虚表的布局属于 Rust 编译器的未公开实现细节,没有进入语言标准。上述代码仅适用于学习虚表工作原理,生产环境请勿依赖,未来编译器版本可能会修改布局。

内容的提问来源于stack exchange,提问作者Danila

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 17:48:08