我有一个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());
}
}
但是,我无法打印出_test_str
并且上面程序的输出很简单
string buffer size without nul terminator: 0
如果我将_test_str
传递给某些C函数,并且看到它是一个空字符串。我做错了什么?
谢谢!
答案 0 :(得分:5)
您要在与创建指向其的指针相同的语句中创建CString
。 CString
拥有但未绑定到变量,因此它仅存在于封闭语句中,从而导致指针变为无效。 documentation for 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
表达式被求值后立即释放了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
}
如果使用原始指针,则需要格外小心,以确保它们始终指向实时数据。引入变量是精确控制数据生存时间的最佳方法-从变量的初始化到变量超出范围的那一刻,数据就会生存。