如何从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 ()); } }
关键说明
胖指针的正确解析:
Rust 中dyn Trait对应的胖指针在内存中是两个连续的usize:第一个指向数据,第二个指向虚表。通过#[repr(C)]定义的FatPtr结构体可以保证内存布局和胖指针完全一致,从而安全地拆分出两个指针。虚表的布局规则:
rustc 实现的虚表固定包含以下字段(顺序不可变):- 第一个字段:析构函数指针(用于清理 dyn 类型实例)
- 第二个字段:类型的大小(对应
std::mem::size_of::<MyData>()) - 第三个字段:类型的对齐值(对应
std::mem::align_of::<MyData>()) - 后续字段:按 trait 中方法声明的顺序排列的函数指针
注意事项:
虚表的布局属于 Rust 编译器的未公开实现细节,没有进入语言标准。上述代码仅适用于学习虚表工作原理,生产环境请勿依赖,未来编译器版本可能会修改布局。
内容的提问来源于stack exchange,提问作者Danila
相关产品推荐
相关产品推荐

