I have a C function that expects *const std::os::raw::c_char
and I have done the following in 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());
}
}
However, I cannot get _test_str
print out and the output of the above program is simply
string buffer size without nul terminator: 0
If I pass the _test_str
into some C function and see it is an empty string. What did I do wrong?
You are creating a
CString
in the same statement as creating a pointer to it. TheCString
is owned but not bound to a variable so it only lives as long as the enclosing statement, causing the pointer to become invalid. This is specifically warned about by the documentation foras_ptr
:You can fix the problem by introducing variables which will live for the entire function, and then create pointers to those variables:
If you are working with raw pointers, you need to be extra careful that they are always pointing at live data. Introducing a variable is the best way to control exactly how long that data lives - it will live from the initialization of the variable to the moment the variable goes out of scope.