2015-07-17 12 views
6

Przykładowy kod poniżejJak sprawdzić, czy wskaźnik funkcji przekazywane z C nie jest NULL

Rust część:

#[no_mangle] 
pub extern fn call_c_function(value: i32, fun: fn(i32) -> i32) -> i32 { 
    fun(value) 
} 

I część C:

int32_t call_c_function(int32_t value, int32_t (*fun)(int32_t)); 

int32_t triple(int32_t x) 
{ 
    return x*3; 
} 

int main(int argc, char *argv[]) 
{ 
    int32_t value = 3; 
    int32_t result = call_c_function(value, triple); 

    printf("%d tripled is %d\n", value, result); 

    call_c_function(0, NULL); // Crash here 

    return EXIT_SUCCESS; 
} 

oczywiście drugiego naboru z call_c_function ulegnie awarii. Rust kompilator nie będzie narzekał na niebezpieczny kod wewnątrz call_c_function, ponieważ z rdzy punktu widzenia ten kod jest bezpieczny. Również nie wolno po prostu napisać:

if !fun.is_null() { 
    fun(value) 
} 

ponieważ fun typ jest fn(i32) -> i32 (nie jest to wskaźnik).

Moje pytanie brzmi: w jaki sposób mogę chronić call_c_function przed NULL dereferencją wskaźnika? Czy istnieje sposób sprawdzenia, czy wywołanie zwrotne przekazane z C nie jest poprawne?

Może muszę zmienić definicję call_c_function?

+0

Tak, po prostu sprawdzić, czy zabawa == NULL. Lub zero, jeśli NULL nie jest rzeczą w rdzą. Pamiętajcie, nie znam rdzy bardzo dobrze, ale tak można to zrobić w C. – rost0031

+2

Zobacz tutaj: http://doc.rust-lang.org/book/ffi.html#the-%22nullable-pointer -optymalizacja% 22 – Adrian

+0

@Adrian Thx, tego właśnie szukałem! – ldanko

Odpowiedz

9

Można użyć Option<...> do reprezentowania zerowalnych wskaźników funkcji. Niepoprawna jest wartość NULL dla wartości typu fn(...), więc w przypadku takich przypadków wymagane jest opakowanie Option.

Na przykład

#[no_mangle] 
pub extern fn call_c_function(value: i32, fun: Option<fn(i32) -> i32>) -> i32 { 
    if let Some(f) = fun { f(value) } 
} 

Jednak nie na dodatkowym punkcie: fun jest funkcją C, ale typ fn(...) jest funkcją Rust. Oni nie są bezpośrednio kompatybilne (np ich konwencje telefoniczne różnią), trzeba być przy użyciu extern "C" fn(...) (aka extern fn(...)) typ podczas interakcji z wskaźników funkcji C:

#[no_mangle] 
pub extern fn call_c_function(value: i32, fun: Option<extern fn(i32) -> i32>) -> i32 { 
    if let Some(f) = fun { f(value) } 
} 
Powiązane problemy