構造体メンバーの場合、offsetof
Cと同様に、Rustでを計算することができoffsetof
ます。
これは構造体フィールドでは機能しますが、列挙型とそのバリアントメンバーに対してこれを行う方法に相当するものを見つけることができませんでした。
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));
このためのマクロを書き込もうとしたときに、引数の結合で問題が発生した::
ため、その部分を解決する方法がわかりませんでした。
列挙型のバリアントは、構造体フィールドとは大きく異なります。列挙型バリアントには、列挙型のタイプとは異なる一意のタイプはありません。Rustコンパイラの内部でさえ、列挙型は列挙型の判別式を含めて表されます。これは、列挙型バリアントの列挙自体へのオフセットがゼロであることを意味します。
列挙型バリアントのフィールドのオフセットが必要になる可能性が高くなります。列挙型バリアントのフィールドへの参照を取得する唯一の方法は列挙型の値と一致することであるため、一致する有効な列挙型値が必要になるため、構造体フィールドオフセットで使用される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);
複数のフィールドを持つ列挙型構造体バリアントおよび列挙型タプルバリアントに対してこのマクロを実装するのは、読者に任されています。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加