string - 将 Path 转换为 *c_char 的最直接方法是什么?

标签 string rust ffi

给定一个 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 不允许您以平台无关的方式将 PathOsStr 转换为 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/

相关文章:

c - 将 C 预处理器翻译成 Rust

generics - 如何返回具有单位数据类型的结构?

rust - 如何在没有 Box::from_raw 的情况下将 *mut *mut c_void 转换为 &str?

c++ - OCaml 可以用作 C++ 的脚本语言吗?

haskell - LIRC 与 Haskell 的接口(interface)

c++ - 拆分包含逗号分隔条目的字符串流

c# - 如何将多字符串与 C# 字符串集合相互转换?

JavaScript 查找字符串的 "newest"版本

java - 正确格式化 Java 字符串以适应 JavaScript 变量

rust - Rust 元组参数的执行顺序是什么?