2014-09-30 14 views
13

Być może nie opisałem poprawnie mojego tytułu pytania, w razie potrzeby edytuj go.Utwórz interfejs ze wskaźnikami funkcji C w Rust

Próbuję skrzyni interfejs rdzy LXC library, który jest napisany w C

Mam powodzeniem zwane proste funkcje jak lxc_get_version lub lxc_container_new ale nie mogę uzyskać dostęp do funkcji opisanych w struct lxc_container bloku.

Tutaj jest część mojego kodu:

#[link(name = "lxc")] 
extern { 
    // LXC part 
    fn lxc_get_version() -> *const c_char; 
    fn lxc_container_new(name: *const c_char, configpath: *const c_char) -> LxcContainer; 

    // LXC container parts 
    fn is_defined(container: &LxcContainer) -> bool; 
} 

I tu jest błąd:

note: test.o: In function `LxcContainer::is_defined::heb2f16a250ac7940Vba': 
test.0.rs:(.text._ZN12LxcContainer10is_defined20heb2f16a250ac7940VbaE+0x3e): undefined reference to `is_defined' 

EDIT: udało mi że funkcje wewnątrz struktur C nazywa wskaźników funkcji. Próbowałem google coś jak "Wskaźnik funkcji Rust C", ale bez powodzenia.

Odpowiedz

20

Kiedy widzisz coś takiego (w C):

struct S { 
    void (*f)(int, long) 
} 

oznacza to, że struktura S zawiera pole o nazwie f który jest wskaźnikiem do funkcji. Nie oznacza to, że sama biblioteka udostępnia funkcję o nazwie f. Na przykład, jest to ważne:

void some_function_1(int x, long y) { ... } 

void some_function_2(int a, long b) { ... } 

int main() { 
    struct S s1; s1.f = some_function_1; 
    struct S s2; s2.f = some_function_2; 
} 

Tutaj struct instancja s1 zawiera wskaźnik do some_function_1 i s2 zawiera wskaźnik do some_function_2.

Podczas pisania wiązania FFI w Rust dla niektórych bibliotek C zazwyczaj definiuje się odpowiedniki Rust dla struktur C. Niektóre narzędzia, takie jak rust-bindgen, mogą to zrobić automatycznie. W twoim przypadku trzeba będzie napisać coś takiego:

#[repr(C)] 
struct LxcContainer { 
    name: *mut c_char, 
    configfile: *mut c_char, 
    // ... 
    numthreads: c_int, 
    // ... 
    is_defined_f: extern fn(c: *mut LxcContainer) -> bool, 
    state_f: extern fn(c: *mut LxcContainer) -> *const c_char, 
    // ... 
} 

Oznacza to, że dziwnie wyglądający funkcyjne C typy wskaźnika odpowiada extern fn typów wskaźnik funkcji w Rust. Można również napisać extern "C" fn(...) -> ..., ale kwalifikator "C" jest domyślny, więc nie jest wymagany.

Będziesz musiał napisać coś takiego nazwać te funkcje:

impl LxcContainer { 
    fn is_defined_f(&mut self) -> bool { 
     unsafe { 
      (self.is_defined_f)(self as *mut LxcContainer) 
     } 
    } 
} 

musisz rzucać odniesienie do surowego wskaźnik i trzeba także owinąć self.is_defined_f w nawiasach w celu disambiguate między wywołanie metody i dostęp do pola.

Możesz znaleźć więcej na FFI w Rust here. Wskaźniki funkcji są jednak bardzo krótko wyjaśnione.

+0

Dziękuję za odpowiedź, mogę teraz uzyskać dostęp do wskaźników funkcji. Napisałem strukturę dla reprezentacji C i otoki dla reprezentacji Rust wokół niej. Niestety nie mogę nawiązać połączenia z 'is_defined', ponieważ nie mogę przekazać struktury LxcContainer do działania jako * LxcContainer. Wystąpił błąd deskryptora. Czy mógłbyś dodać jakiś przykład wywołania funkcji do swojej odpowiedzi? Dziękuję Ci. – bbrodriges

+0

@bbrodriges, przepraszam za spóźnioną odpowiedź, ale zaktualizowałem swoją odpowiedź na przykładzie sposobu wywoływania funkcji przechowywanych w polach struktury. –

Powiązane problemy