2016-08-07 16 views
2

Ich habe einen Typ:Wie bekomme ich einen Zeiger auf eine umgebende Struktur von einem Zeiger auf ein Mitglied?

struct Foo { 
    memberA: Bar, 
    memberB: Baz, 
} 

und einen Zeiger, ich weiß, ein Zeiger auf memberB in Foo ist:

p: *const Baz 

Was ist der richtige Weg ist, einen neuen Zeiger p: *const Foo, die auf die Punkte zu bekommen Originalstruktur Foo?

Meine aktuelle Implementierung ist die folgende, die ich bin mir ziemlich sicher, dass auf Grunde die Dereferenzierung von (p as *const Foo) undefiniertes Verhalten aufruft, wo p auf ein Foo keinen Zeiger ist:

let p2 = p as usize - 
    ((&(*(p as *const Foo)).memberB as *const _ as usize) - (p as usize)); 

Dieser Teil von FFI ist - I kann den Code nicht einfach umstrukturieren, um zu vermeiden, dass dieser Vorgang ausgeführt werden muss.

Dies ist sehr ähnlich zu Get pointer to object from pointer to some member aber für Rust, die, soweit ich weiß, keine offsetof Makro hat.

+0

Warum kann man nicht in einem '* const Foo' an den C-Code übergeben Sie einfach statt? – Shepmaster

+0

In diesem speziellen Beispiel gibt mir der FFI ein '* const Baz', und ich erwarte, dass ich das Originalobjekt daraus abrufe. Wenn ich das ursprüngliche Objekt einfach weitergeben könnte, würde ich das tun, aber das ist keine Option. – Mystor

Antwort

4

Der dereferenzieren Ausdruck erzeugt einen L-Wert, aber der L-Wert ist nicht wirklich las aus, sind wir einfach darauf Zeiger Mathematik zu tun, so in Theorie, soll es gut definiert werden. Das ist nur meine Interpretation.

Meine Lösung beinhaltet die Verwendung eines Null-Zeigers, um den Offset zum Feld abzurufen, also ist es ein bisschen einfacher als Ihr, da es eine Subtraktion vermeidet (wir würden 0 subtrahieren). Ich glaube, ich sah einige C-Compiler/Standardbibliotheken Umsetzung offsetof im Wesentlichen durch die Adresse eines Feldes von einem Null-Zeiger zurückkehrt, das ist es, was die folgende Lösung inspiriert.

fn main() { 
    let p: *const Baz = 0x1248 as *const _; 
    let p2: *const Foo = unsafe { ((p as usize) - (&(*(0 as *const Foo)).memberB as *const _ as usize)) as *const _ }; 
    println!("{:p}", p2); 
} 

Wir können auch unsere eigenen offset_of! Makro definieren:

macro_rules! offset_of { 
    ($ty:ty, $field:ident) => { 
     unsafe { &(*(0 as *const $ty)).$field as *const _ as usize } 
    } 
} 

fn main() { 
    let p: *const Baz = 0x1248 as *const _; 
    let p2: *const Foo = ((p as usize) - offset_of!(Foo, memberB)) as *const _; 
    println!("{:p}", p2); 
} 
Verwandte Themen