2016-07-13 22 views
2

Ich versuche, auf die verschiedenen Felder der FILE Struktur von libc zuzugreifen.Wie greife ich auf Felder von * mut libc :: FILE zu?

FILE Implementierung in Rust nach der Speicherzuordnung in stdio.h:

#[repr(C)] 
pub struct FILE { 
    pub _p: libc::c_char, 
    pub _r: libc::c_int, 
    pub _w: libc::c_int, 
    pub _flags: libc::c_short, 
    pub _file: libc::c_short, 
    ... 
} 

, wenn sie mit FILE s in libc Arbeit kommen sie in der mut * Variante, und das ist irgendwie in der Art und Weise die Felder zuzugreifen. Der folgende Code triggert error: attempted access of field _flags on type '*mut FILE', but no field with that name was found.

let stdout = libc::fdopen(libc::STDOUT_FILENO, &('w' as libc::c_char)); 
let is_unbuffered = (fp._flags & libc::_IONBF as i16) != 0 

Eine Variable vom Typ FILE ohne die mut * Variante funktioniert, aber ich brauche es mit mut * Arbeit zu bekommen.

Antwort

3

FILE als opaque type definiert ist, das heißt:

pub enum FILE {} 

So gibt kein Feld für den Zugriff ist (auch die Rohzeiger dereferencing).


Ich denke, dass es keine gute Idee ist, direkt die Bereiche FILE Struktur zugreifen, auch in C. sollten Sie versuchen, eine Funktion auf stdio.h zu finden, das zu tun, was Sie wollen.


Auf jeden Fall ist eine Abhilfe Ihre eigene Definition von FILE zu schaffen und eine &mut von fp zu erhalten:

#[repr(C)] 
pub struct MY_FILE { 
    pub _p: libc::c_char, 
    pub _r: libc::c_int, 
    pub _w: libc::c_int, 
    pub _flags: libc::c_short, 
    pub _file: libc::c_short, 
    // ... 
} 

// ... 

unsafe { 
    let fp = libc::fdopen(libc::STDOUT_FILENO, &('w' as libc::c_char)); 
    let fp = &mut *(fp as *mut MY_FILE); 
    let is_unbuffered = (fp._flags & libc::_IONBF as i16) != 0; 
} 

Beachten Sie, dass, wenn Sie nicht die richtige Definition für MY_FILE nicht verwenden, werden Sie einige bekommen Mülldaten oder sogar ein segfault.

+0

danke. das '& mut *' Bit war der fehlende Teil in meinem Code. Kannst du etwas darüber sagen, was das ist? Ich bin immer noch im Dunkeln, wenn es um Zeiger und Referenzen geht, wirklich schwer von einer Java/PHP/Python-Welt – hansaplast

+0

zusätzliche Frage: meine Struktur jetzt "funktioniert nicht": '_flags' ist immer 0. Haben Sie irgendwelche Hinweise, wie das zu beheben? Hier ist stdio.h auf OSX: https://gist.github.com/philippkeller/3921705e7b5d0ef5d394501496d146fe Ich sehe einfach nicht, was das Problem ist, IMO auf _flags direkt alle Mitglieder zugreifen und mit '_flags' müssen korrekt sein, die folgenden können falsch sein (oder sogar weggelassen werden) – hansaplast

+0

'fdopen' gibt einen [rohen Zeiger] zurück (https://doc.rust-lang.org/stable/std/primitive.pointer.html). Sie können nicht viel mit einem rohen Zeiger machen, so erhalten wir eine veränderbare Referenz ('& mut') von ihr (' * 'dereferenzieren den Zeiger, der einen Wert vom Typ' FILE' gibt, '& mut' erhalten einen veränderlichen Verweis auf den' FILE "Wert).Ich denke, es ist keine gute Idee, direkt auf die Felder der 'FILE'-Struktur zuzugreifen, selbst in' C'. Vielleicht sollten Sie eine andere Frage stellen und erklären, was Sie tun möchten (testen Sie, ob eine Datei gepuffert ist?). – malbarbo

0

Der Zeiger selbst hat keine Attribute, die Struktur, auf die er zeigt.

Was dies bedeutet, ist, dass Sie *fp._flags, nicht fp._flags (unter der Annahme fp vom Typ *mut FILE) zugreifen müssen.

Darüber hinaus müssen Sie wahrscheinlich den Zugriff in einen unsafe-Block umbrechen, da die Dereferenzierung eines rohen Zeigers immer eine unsichere Operation ist. so etwas wie dieses versuchen:

let flags = unsafe { (*fp)._flags }; 
let is_unbuffered = (flags & libc::_IONBF as i16) != 0;