如何以字节为单位获取枚举成员的指针偏移量?

时间:2017-01-24 08:27:07

标签: pointers rust

对于struct成员,可以计算Rust中的offsetof,类似于C' offsetof

虽然这适用于struct字段,但我无法找到与枚举及其变体成员相同的方法。

通过与IRC上的开发人员交谈,不能保证枚举的所有成员都是一致的:

如何计算枚举成员的偏移量?

对于实例,它可以像这样工作:

enum Test { A(u8), B(f64) };

fn test_me(a: Test) {
    if let Test::A(b) = a {
        // we could find the offset between 'a' and 'b' here.
        // but how to do this without instantiating variables?
        println("{}", (b as *const _) as usize - (a as *const _) as usize);
    }
}

然而,目标是能够通过仅检查类型来完成此操作,因此它可以编译为常量,例如:

println("{}", offset_of_enum!(Test, A));

在尝试为此编写宏时,我遇到了::加入参数的问题,因此我不确定如何解决该部分。

1 个答案:

答案 0 :(得分:4)

Enum变体与struct字段有很大不同。枚举变体不具有与枚举类型不同的唯一类型。甚至在Rust编译器内部,枚举变量也包括枚举的判别式。这意味着enum变量对枚举本身的偏移量为零。

您更希望获得枚举变体字段的偏移量。由于获取枚举变量字段引用的唯一方法是匹配枚举值,因此您需要一个有效的枚举值来匹配,因此您无法使用在struct field offset计算中使用的nullpointer技巧。

macro_rules! offset_of {
    ($($tt:tt)*) => {
        {
            let base = $($tt)*(unsafe { ::std::mem::uninitialized() });
            let offset = match base {
                $($tt)*(ref inner) => (inner as *const _ as usize) - (&base as *const _ as usize),
                _ => unreachable!(),
            };
            ::std::mem::forget(base);
            offset
        }
    }
}
enum Foo {
    A(i32),
    B(u8),
}
let offset = offset_of!(Foo::A);

由读者为枚举结构变体和具有多个字段的枚举变体实现此宏。