2016-08-15 8 views
5

std::path::Pathがある場合、これをヌルで終端されたstd::os::raw::c_charに変換する最も直接的な方法は何ですか? (パスをとるC関数に渡すため)。Pathを* 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()); 
} 

非常に多くの中間ステップを避ける方法はありますか?

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

それは 'PATH'はCの文字列に変換することができることを前提とし、正確ではありません。プラットフォームは異なるエンコーディングを使用できます。これらの抽象化が最初に存在する理由です。 UNIX系システムに限定している場合、['OsStrExt'](https://doc.rust-lang.org/std/os/unix/ffi/trait.OsStrExt.html)があります。 – Shepmaster

+0

また、Cの文字列はそれを必要としませんが、あなたはUTF-8でなければならない 'String'にも変換しています。 – Shepmaster

答えて

4

これは見た目ほど簡単ではありません。あなたが提供していない情報が1つあります:C関数はパスが入ることを期待していますか? Linuxの

、パスはバイトの「ただ」アレイ(0は無効である)であり、アプリケーションは通常、それらを解読しようとしないでください。 (ただし、彼らは通常、多くの場合、UTF-8エンコーディングを使用します。現在のロケールに応じてそれらを解読しようとした場合には、ユーザー、それらを表示するなどの特定のエンコーディングでそれらをデコードする必要があります。)

「ユニコード」(UTF-16)を使用する「ANSI」コードページとバリエーションを使用するAPI関数のばらつきがあるため、Windows上で

は、それは、より複雑です。さらに、Windowsでは、UTF-8を「ANSI」コードページとして設定することはできません。これは、ライブラリーは、特にUTF-8を期待し、それをUTF-8でエンコードされたパスを渡して、ネイティブコード化自体へのパスを変換しない限り、(はASCII文字のみを含む文字列のために働くを見えるかもしれませんが)確かに間違っていることを意味しています。

(私は他のプラットフォームについては知りませんが、それはすでに十分に厄介です。)

錆で、PathOsStrのための単なるラッパーです。 OsStrは、文字列が実際に有効なUTF-8であるときにUTF-8と互換性があるプラットフォーム依存表現を使用しますが、UTF-8以外の文字列は不特定のエンコーディングを使用します(Windowsでは実際にWTF-8を使用しますが、契約上、Linuxでは、それはそのままのバイト配列です)。

C関数へのパスを渡す前に、文字列がどのエンコーディングになるかを判断し、Rustのエンコーディングと一致しない場合は、変換する前に変換する必要があります。CString 。錆はPathまたはOsStrstr以外にプラットフォームに依存しない方法で変換することはできません。 Unixベースのターゲットでは、OsStrExt特性が使用可能で、OsStrへのアクセスをバイトスライスとして提供します。

OsStrto_cstringメソッドを提供するために使用された錆ですが、Windowsでは不適切な動作であることが判明したので、Rust 1.6.0で非難されました(UTF-8エンコードされたパスしかし、Windows APIはそれをサポートしていません!)。

+2

ロケールはLinux上で体系的に推測されますが、実際にはパスエンコーディングには関係しません。パスは0以外の任意のバイトでも構いません。 – bluss