在C语言中,一个指向结构体的指针可以转换为指向其第一个成员的指针,反之亦然。也就是说,结构体的地址被定义为其第一个成员的地址。
struct Base { int x; };
struct Derived { struct Base base; int y; };
int main() {
struct Derived d = { {5}, 10 };
struct Base *base = &d.base; // OK
printf("%d\n", base->x);
struct Derived *derived = (struct Derived *)base; // OK
printf("%d\n", derived->y);
}
这通常用于实现类似 C++ 的继承。
如果结构体使用了 repr(C)
(使其字段不被重新排列),在 Rust 中是否允许相同的操作呢?
#[derive(Debug)]
#[repr(C)]
struct Base {
x: usize,
}
#[derive(Debug)]
#[repr(C)]
struct Derived {
base: Base,
y: usize,
}
// safety: `base` should be a reference to `Derived::base`, otherwise this is UB
unsafe fn get_derived_from_base(base: &Base) -> &Derived {
let ptr = base as *const Base as *const Derived;
&*ptr
}
fn main() {
let d = Derived {
base: Base {
x: 5
},
y: 10,
};
let base = &d.base;
println!("{:?}", base);
let derived = unsafe { get_derived_from_base(base) }; // defined behaviour?
println!("{:?}", derived);
}
这段代码可行,但它是否一直可行,并且是否符合定义的行为?