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



我有一个需要*const std::os::raw::c_char的 C 函数,我在 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("%sn").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());
}
}

但是,我无法打印_test_str并且上述程序的输出很简单

string buffer size without nul terminator: 0

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

您正在创建与创建指向它的指针相同的语句中创建CStringCString是拥有的,但未绑定到变量,因此它只与封闭语句一样长,从而导致指针无效。as_ptr的文档对此进行了特别警告:

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

use std::ffi::{CString};
let ptr = CString::new("Hello").expect("CString::new failed").as_ptr();
unsafe {
// `ptr` is dangling
*ptr;
}

发生这种情况是因为as_ptr返回的指针不携带任何生存期信息,并且在计算CString::new("Hello").expect("CString::new failed").as_ptr()表达式后立即释放CString

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

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("%sn").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
}

如果您使用的是原始指针,则需要格外小心,因为它们始终指向实时数据。引入变量是准确控制数据生存时间的最佳方式 - 它将从变量初始化到变量超出范围的那一刻。

最新更新