Arbeiten mit c_void in einem FFI
Ich bin kämpfen, mit übergabe eines struct durch eine FFI, die nimmt void und Lesen Sie es zurück an das andere Ende.
Die Bibliothek in Frage libtsm, ein terminal-Zustand-Maschine. Es ermöglicht Ihnen, feed-Eingang und dann finden Sie heraus, in welchem Zustand sich ein terminal wäre nach der Eingabe.
Erklärt er seinen draw Funktion als:
pub fn tsm_screen_draw(con: *tsm_screen, draw_cb: tsm_screen_draw_cb, data: *mut c_void) -> tsm_age_t;
wo tsm_screen_draw_cb ist ein callback implementiert werden, indem die Benutzer der Bibliothek mit der Signatur:
pub type tsm_screen_draw_cb = extern "C" fn(
con: *tsm_screen,
id: u32,
ch: *const uint32_t,
len: size_t,
width: uint,
posx: uint,
posy: uint,
attr: *tsm_screen_attr,
age: tsm_age_t,
data: *mut c_void
);
Ist der wichtige Teil hier ist die data
parameter. Es ermöglicht dem Benutzer zu übergeben, die durch einen Zeiger auf eine selbst implementierte Zustand, um es zu manipulieren und verwenden Sie es nach der Zeichnung. Eine einfache Struktur:
struct State {
state: int
}
wie würde ich das richtig? Ich bin unsicher, wie man richtig cast der Zeiger auf die struct void und zurück.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Können Sie nicht wirken, eine struct zu
c_void
, aber können Sie werfen einen Referenz, um die Struktur zu*mut c_void
- und Rückseite mit einigen Zeiger-casts:Ist es auch möglich, mit
std::mem::transmute()
Funktion cast zwischen Zeigern, aber es ist viel zu mächtiges Werkzeug, als hier wirklich gebraucht und sollte vermieden werden wenn möglich.Beachten Sie, dass Sie müssen besonders vorsichtig Gießen eine unsichere Zeiger wieder zu einer Referenz. Wenn
tsm_screen_draw
ruft die callback-in einem anderen thread oder speichert ihn in einer globalen variable und dann eine andere Funktion Aufrufe, dannstate
lokale variable kann auch außerhalb des Bereichs, wenn der callback aufgerufen wird, die zum Absturz Ihres Programms.transmute
: es ist sehr mächtig, und so leicht versehentlich umwandeln etwas falsch. Sie behandeln können die Zeiger direkt mitas
z.B.let data = &mut *(data as *mut State);
, undlet state_ptr = &mut state as *mut _ as *mut c_void;
. (Vor allem schreiben&mut *...
da, mit dem Sie garantiert mit einem Zeiger, im Gegensatz zutransmute
.)state
sind schon aus dem Umfang und zerstört wurde. Überprüfen Sie, dass der callback nur aufgerufen wird, wennstate
ist noch am Leben.Screen::open()
oderscreen.resize()
es nicht einmal betreten der Schleife.