2015-07-17 7 views
6
ist

Beispielcode untenWie kann man überprüfen, ob Funktionszeiger von C bestanden nicht-NULL

Der Teil Rust:

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

Und der C-Teil:

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; 
} 

Natürlich zweiten Anruf von call_c_function wird abstürzen. Rust Compiler wird nicht über unsicheren Code innerhalb call_c_function beschweren, weil aus Sicht des Rosts dieser Code sicher ist. Auch ist es nicht einfach schreiben erlaubt:

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

weil fun Typ ist fn(i32) -> i32 (es ist kein Zeiger).

Also meine Frage ist, wie kann ich call_c_function gegen NULL-Zeigerdereferenz schützen? Gibt es eine Möglichkeit zu überprüfen, ob der Rückruf von C nicht gültig ist?

Vielleicht muss ich call_c_function Definition ändern?

+0

Ja, genau prüfen, ob Spaß == NULL. Oder Null, wenn NULL im Rost kein Ding ist. Wohlgemerkt, ich kenne Rost nicht sehr gut, aber so würde man es in C. machen. – rost0031

+2

Siehe hier: http://doc.rust-lang.org/book/ffi.html#the-%22nullable-pointer -optimization% 22 – Adrian

+0

@Adrian Thx, das habe ich gesucht! – ldanko

Antwort

9

Sie können Option<...> verwenden, um funktionsfähige Nullzeiger darzustellen. Es ist falsch, einen NULL-Wert für einen Wert vom Typ fn(...) zu haben, sodass der Wrapper Option für solche Fälle erforderlich ist.

Zum Beispiel

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

Allerdings gibt es auf Extra-Punkt: fun ist eine C-Funktion, aber der Typ fn(...) ist eine Rust Funktion. Sie sind nicht direkt kompatibel (zum Beispiel ihrer Aufrufkonventionen unterscheiden), muss man den extern "C" fn(...) (aka extern fn(...)) Typen zu verwenden, wenn mit C Funktionszeigern der Interaktion:

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