2016-08-15 35 views
5

Biorąc pod uwagę std::path::Path, jaki jest najbardziej bezpośredni sposób przekonwertować to na zakończone znakiem Null std::os::raw::c_char? (do przekazywania do funkcji C, które przechodzą ścieżkę).Jaki jest najbardziej bezpośredni sposób przekonwertowania ścieżki na * c_char?

use std::ffi::CString; 
use std::os::raw::c_char; 
use std::os::raw::c_void; 

extern "C" { 
    some_c_function(path: *const c_char); 
} 

fn example_c_wrapper(path: std::path::Path) { 
    let path_str_c = CString::new(path.as_os_str().to_str().unwrap()).unwrap(); 

    some_c_function(path_str_c.as_ptr()); 
} 

Czy można uniknąć tak wielu pośrednich kroków?

Path -> OsStr -> &str -> CString -> as_ptr() 
+0

Nie należy zakładać, że 'Ścieżka' może zostać przekonwertowana na ciąg znaków C. Platformy mogą i używają różnych kodowań; dlatego właśnie te abstrakcje istnieją w pierwszej kolejności. Jeśli ograniczasz się do systemów podobnych do UNIX, istnieje ['OsStrExt'] (https://doc.rust-lang.org/std/os/unix/ffi/trait.OsStrExt.html). – Shepmaster

+0

Zauważ również, że konwertujesz także do 'String', który musi być UTF-8, chociaż ciągi C tego nie wymagają. – Shepmaster

Odpowiedz

4

To nie jest takie proste, jak się wydaje. Jest jedna informacja, której nie dostarczyłeś: jakie kodowanie jest funkcją C oczekującą na ścieżkę?

W systemie Linux ścieżki są "tylko" tablicami bajtów (0 jest niepoprawne), a aplikacje zwykle nie próbują ich dekodować. (Może się jednak zdarzyć, że będą musieli je odkodować za pomocą określonego kodowania, np. Wyświetlić je użytkownikowi, w którym to przypadku zazwyczaj będą próbować je zdekodować zgodnie z bieżącymi ustawieniami regionalnymi, które często będą używać kodowania UTF-8.)

W systemie Windows jest to bardziej skomplikowane, ponieważ istnieją odmiany funkcji API korzystające ze strony kodowej "ANSI" i odmiany używające "Unicode" (UTF-16). Ponadto system Windows nie obsługuje ustawiania kodu UTF-8 jako strony kodowej "ANSI". Oznacza to, że jeśli biblioteka nie oczekuje od UTF-8 i konwertuje ścieżkę do samego kodowania macierzystego, przekazanie jej ścieżki kodowanej w UTF-8 jest zdecydowanie błędne (chociaż może się wydawać, że działa dla ciągów zawierających tylko znaki ASCII).

(nie wiem o innych platformach, ale to już wystarczająco brudny.)

w Rust, Path jest tylko nakładką na OsStr. OsStr używa reprezentacji zależnej od platformy, która jest zgodna z UTF-8, gdy łańcuch jest rzeczywiście poprawnym UTF-8, ale ciągi nie-UTF-8 używają nieokreślonego kodowania (w Windowsie, to faktycznie używa WTF-8, ale to nie jest umowny, w Linuksie jest to po prostu tablica bajtów).

Zanim przejdziesz ścieżką do funkcji C, musisz określić, jakiego kodowania oczekuje ciąg znaków, a jeśli nie pasuje do kodowania Rust, musisz go przekonwertować przed zawinięciem w CString . Rust nie pozwala konwertować Path lub OsStr na nic innego niż str w sposób niezależny od platformy. W przypadku celów opartych na Uniksie funkcja OsStrExt jest dostępna i zapewnia dostęp do OsStr jako kawałek bajtów.

Rdza używana jako metoda to_cstring na OsStr, ale nigdy nie była ustabilizowana i została uznana za przestarzałą w wersji 1.6.0, ponieważ zdano sobie sprawę, że zachowanie było nieodpowiednie dla systemu Windows (zwróciła ścieżkę zakodowaną w formacie UTF-8; , ale interfejsy API systemu Windows tego nie obsługują!).

+2

Locale byłoby systematyczne domysły na Linuksie, ale nie jest tak naprawdę związane z kodowaniem ścieżki. Ścieżki mogą być dowolnymi bajtami oprócz 0. – bluss