从 Rust 向 C 函数提供“char **”参数?

Rog*_*mbe 3 rust

我有一个 C 函数(简化)如下所示:

static char buffer[13];

void get_string(const char **s) {
    sprintf(buffer, "Hello World!");
    *s = buffer;
}
Run Code Online (Sandbox Code Playgroud)

我已经在 Rust 中声明了它:

extern pub fn get_string(s: *mut *const c_char);
Run Code Online (Sandbox Code Playgroud)

但我无法弄清楚调用它所需的咒语,并将结果转换为 Rust 字符串。我尝试过的所有方法要么无法编译,要么导致SEGV。

有什么指点吗?

Tim*_*ann 5

首先,charRust 中的a并不等同charC 中的a :

char类型代表单个字符。更具体地说,由于“字符”在 Unicode 中不是一个明确定义的概念,因此它char是一个“ Unicode 标量值”,它类似于“ Unicode 代码点”,但不相同。

在 Rust 中,您可以使用u8或 ,i8具体取决于操作系统。您可以std::os::raw::c_char为此使用:

相当于C的char类型。

C 的char类型与Rust 的char类型完全不同;Rust 的类型代表一个 unicode 标量值,而 C 的char类型只是一个普通的整数。该类型始终为 或i8u8因为该类型被定义为一个字节长。

C 字符最常用于生成 C 字符串。与 Rust 不同,Rust 中字符串的长度包含在字符串旁边,而 C 字符串则用字符 标记字符串的结尾'\0'。请参阅CStr获取更多信息。

首先,我们需要一个可以传递给函数的变量:

let mut ptr: *const c_char = std::mem::uninitialized();
Run Code Online (Sandbox Code Playgroud)

要传递它,*mut您只需使用引用即可:

get_string(&mut ptr);
Run Code Online (Sandbox Code Playgroud)

现在使用*const c_char创建一个CStr

let c_str = CStr::from_ptr(ptr);
Run Code Online (Sandbox Code Playgroud)

要将其转换为 a,String您可以选择:

c_str.to_string_lossy().to_string()
Run Code Online (Sandbox Code Playgroud)

或者

c_str().to_str().unwrap().to_string()
Run Code Online (Sandbox Code Playgroud)

String但是,如果您确实不需要,则不应使用。大多数情况下,a 就Cow<str>可以满足需求。它可以通过以下方式获得c_str.to_string_lossy()

如果 的内容CStr是有效的 UTF-8 数据,则该函数将返回Cow::Borrowed([&str])带有相应[&str]切片的 a。否则,它将替换任何无效的 UTF-8 序列U+FFFD REPLACEMENT CHARACTER并返回Cow::[Owned](String)结果。

您可以在Playground上看到这一点。这个 Playground显示了 的用法to_string_lossy()