Passer une variable Rust à une fonction C qui s’attend à pouvoir la modifier

J’écris une couche Rust sécurisée avec laquelle je peux appeler des fonctions à partir d’une bibliothèque C dans Rust. J’ai généré les liaisons non sûres avec rust-bindgen , mais je suis un peu confus quant aux différences entre la façon dont Rust et C travaillent en ce qui concerne le passage de pointeurs.

La fonction C ressemble à ceci:

bool imeGet(unsigned char address, int *value); 

Il lit un capteur I2C à l’ address , stocke le résultat en value et renvoie TRUE en cas de succès.

Bindgen a la fonction Rust ressemblant à ceci:

 pub fn imeGet(address: ::std::os::raw::c_uchar, value: *mut ::std::os::raw::c_int) -> bool; 

Et mon interlocuteur sûr ressemble à ceci actuellement:

 pub fn ime_get(addr: u8) -> i32 { let v: &mut i32 = 0; unsafe { imeGet(addr, v); *v } } 

Ce code ne comstack pas à cause de = 0 . Quand je n’avais pas cela, le compilateur s’est plaint de ce que v n’avait peut-être pas été initialisé. Mon intention est de gérer le succès de cette fonction et de simplement renvoyer la valeur i32 .

Comment gérer le comportement de l’argument *mut c_int ? J’ai essayé de déclarer v tant que référence et de renvoyer sa valeur déréférencée (ci-dessus), mais cela ne fonctionne pas. J’ai également essayé de retourner v , mais je ne veux pas vraiment que la valeur de retour rest modifiable.

Je suis assez nouveau pour Rust, mais j’ai une bonne formation en C, ce qui peut être une source de confusion pour moi.

mais j’ai un fond décent en C

L’équivalent moral de votre code Rust est:

 int *v = NULL; imeGet(addr, v); *v 

Cela provoquera une erreur car le code C va probablement déréférencer cette v pour stocker la valeur, sauf que vous avez passé une valeur NULL, il est donc plus probable que le code va exploser.

Vous devez créer un stockage pour la valeur, puis fournir une référence à ce stockage pour la fonction:

 fn ime_get(addr: u8) -> i32 { let mut v = 0; unsafe { imeGet(addr, &mut v) }; v } 

La solution pour tout type de pointeur utilise ptr::null_mut :

 unsafe { let mut v = std::ptr::null_mut(); takes_a_pointer_pointer(addr, &mut v); v } 

La solution générale pour tout type utilise mem::uninitialized :

 unsafe { let mut v = std::mem::uninitialized(); takes_a_value_pointer(addr, &mut v); v } 

Pour être complet, vous devriez vérifier la valeur de retour:

 fn ime_get(addr: u8) -> Option { let mut v = 0; let success = unsafe { imeGet(addr, &mut v) }; if success { Some(v) } else { None } } 

les différences entre la façon dont Rust et C fonctionnent en ce qui concerne les indicateurs de passage.

Il n’y en a pas vraiment, à ce niveau.