给定一个 std::path::Path
,将其转换为空终止的 std::os::raw::c_char
的最直接方法是什么? (用于传递给采用路径的 C 函数)。
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()
最佳答案
这并不像看起来那么简单。有一条信息您没有提供:C 函数期望路径采用什么编码?
在 Linux 上,路径“只是”字节数组(0 无效),应用程序通常不会尝试解码它们。 (但是,他们可能必须使用特定的编码对其进行解码,例如将它们显示给用户,在这种情况下,他们通常会尝试根据当前的语言环境对其进行解码,这通常会使用 UTF-8 编码。)
在 Windows 上,它更复杂,因为有使用“ANSI”代码页的 API 函数变体和使用“Unicode”(UTF-16) 的变体。此外,Windows 不支持将 UTF-8 设置为“ANSI”代码页。这意味着除非库特别期望 UTF-8 并将路径转换为 native 编码本身,否则将 UTF-8 编码路径传递给它绝对是错误的(尽管它可能看起来适用于仅包含 ASCII 的字符串字符)。
(其他平台不知道,反正已经够乱了)
在 Rust 中,Path
只是 OsStr
的包装器. OsStr
使用平台相关的表示形式,当字符串确实是有效的 UTF-8 时恰好与 UTF-8 兼容,但非 UTF-8 字符串使用未指定的编码(在 Windows 上,它实际上是使用 WTF-8 ,但这不是契约(Contract)规定的;在 Linux 上,它只是字节数组。
在将路径传递给 C 函数之前,您必须确定它希望字符串采用哪种编码,如果它与 Rust 的编码不匹配,则必须先转换它,然后再将其包装在 CString
。 Rust 不允许您以平台无关的方式将 Path
或 OsStr
转换为 str
以外的任何内容。在基于 Unix 的目标上,OsStrExt
trait 可用并提供对 OsStr
作为 byte slice 段的访问。
Rust 用于提供 to_cstring
OsStr
上的方法,但它从未稳定下来,并且在 Rust 1.6.0 中被弃用,因为人们意识到该行为不适合 Windows(它返回一个 UTF-8 编码的路径,但 Windows API 不支持!)。
关于string - 将 Path 转换为 *c_char 的最直接方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38948669/