如何从Rust向C函数提供`char **`参数?

3

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

static char buffer[13];

void get_string(const char **s) {
    sprintf(buffer, "Hello World!");
    *s = buffer;
}

我已经在Rust中声明了它:

extern pub fn get_string(s: *mut *const c_char);

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

有什么指针吗?


1
应该可以使用 这个,更多信息请参见这个答案,也许是一个重复的问题? - Stargateur
1
这个相关问题返回一个字符串,而不是使用输出参数,所以我不知道如何进行调整。您的示例似乎有效;可以将其发布为答案吗? - Roger Lipscombe
我尝试过的所有方法 - 你能展示一些这些尝试吗? - Shepmaster
1
是的,它们是不够的。char **参数和char *返回值之间有区别,int *参数和char **参数之间也有区别。我对Rust很陌生,不知道如何将它们结合起来。 - Roger Lipscombe
你能展示一些尝试的例子吗?不行,因为它们与此无关。这只是一个简单的问题。 - Roger Lipscombe
2个回答

5
首先,Rust中的char并不等同于C语言中的char

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

在Rust中,您可以根据操作系统使用u8i8。您可以使用std::os::raw::c_char来实现此目的:
等同于C的char类型。 C的char类型Rust的char类型完全不同;虽然Rust的类型表示Unicode标量值,但C的char类型只是一个普通整数。该类型将始终为i8u8,因为该类型被定义为一字节长。 C chars最常用于制作C字符串。与Rust不同,在Rust中,字符串的长度包含在字符串旁边,而C字符串使用字符'\0'标记字符串的结尾。有关更多信息,请参见{{link3:CStr}}。
首先,我们需要一个变量,它可以传递给函数:
let mut ptr: *const c_char = std::mem::uninitialized();

要将它作为*mut传递,你只需要使用引用:

get_string(&mut ptr);

现在使用*const c_char来创建一个CStr
let c_str = CStr::from_ptr(ptr);

将其转换为 String,你可以选择:

c_str.to_string_lossy().to_string()

或者

c_str().to_str().unwrap().to_string()

然而,如果您不是真正需要使用String,则不应使用它。在大多数情况下,Cow<str>满足需求。可以通过c_str.to_string_lossy()获得:

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

你可以在Playground上看到它的效果。这个Playground展示了使用to_string_lossy()的情况。

std::mem::uninitialized() 现在已被弃用,请改用 mem::MaybeUninit - Raven

0

结合将Rust变量传递给期望能够修改它的C函数

unsafe { 
    let mut c_buf = std::ptr::null();
    get_string(&mut c_buf);
}

使用如何通过FFI将C字符串转换为Rust字符串并返回?

extern crate libc;

use libc::c_char;
use std::ffi::CStr;
use std::str;

extern "C" {
    fn get_string(s: *mut *const c_char);
}

fn main() {
    unsafe {
        let mut c_buf = std::ptr::null();
        get_string(&mut c_buf);
        let c_str = CStr::from_ptr(c_buf);
        let str_slice: &str = c_str.to_str().unwrap();
        let str_buf: String = str_slice.to_owned(); // if necessary
    };
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接