CString :: new()。unwrap()。as_ptr()给出空的* const c_char

xxk*_*kkk 1 reference ffi rust raw-pointer

我有一个期望的C函数,*const std::os::raw::c_char并且在Rust中完成了以下操作:

use std::os::raw::c_char;
use std::ffi::{CString, CStr};
extern crate libc;

fn main() {
    let _test_str: *const c_char = CString::new("Hello World").unwrap().as_ptr();
    let fmt: *const c_char = CString::new("%s\n").unwrap().as_ptr();
    unsafe { libc::printf(fmt, _test_str); }

    unsafe {
        let slice = CStr::from_ptr(_test_str);
        println!("string buffer size without nul terminator: {}", slice.to_bytes().len());
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,我无法_test_str打印出来,上面程序的输出很简单

string buffer size without nul terminator: 0
Run Code Online (Sandbox Code Playgroud)

如果我将传递给_test_str某些C函数,然后看到它是一个空字符串。我做错什么了?

谢谢!

Pet*_*all 5

CString在与创建指向它的指针相同的语句中创建一个。该CString所拥有,但因此它只能作为长期居住的封闭声明,引起指针变为无效不绑定到一个变量。特别是针对以下文档的as_ptr警告:

例如,当在unsafe块中使用ptr时,以下代码将导致未定义的行为:

use std::ffi::{CString};

let ptr = CString::new("Hello").expect("CString::new failed").as_ptr();
unsafe {
    // `ptr` is dangling
    *ptr;
}
Run Code Online (Sandbox Code Playgroud)

发生这种情况是因为所返回的指针as_ptr不包含任何生存期信息,并且CString在对CString::new("Hello").expect("CString::new failed").as_ptr()表达式求值后立即将其释放。

您可以通过引入将在整个函数中使用的变量来解决问题,然后创建指向这些变量的指针:

fn main() {
    let owned_test = CString::new("Hello World").unwrap();
    let _test_str: *const c_char = owned_test.as_ptr();
    let owned_fmt = CString::new("%s\n").unwrap();
    let fmt: *const c_char = owned_fmt.as_ptr();

    unsafe {
        libc::printf(fmt, _test_str);
    }

    unsafe {
        let slice = CStr::from_ptr(_test_str);
        println!(
            "string buffer size without nul terminator: {}",
            slice.to_bytes().len()
        );
    }

    // owned_fmt is dropped here, making fmt invalid
    // owned_test is dropped here, making _test_str invalid
}
Run Code Online (Sandbox Code Playgroud)

如果使用原始指针,则需要格外小心,以确保它们始终指向实时数据。引入变量是精确控制数据生存期的最佳方法-从变量的初始化到变量超出范围,生命周期将一直存在。