CString and CStr
- Rust course
- Advanced
- Lesson 38/81
- 4 min
Convert C strings with CString and CStr.
CString and CStr
C strings are byte arrays ending with a null byte (\0); Rust strings know their length and may contain \0. The bridge is two types:
CString: an owned string ending with\0; for sending from Rust to C.CStr: a borrowed C string; for reading a pointer coming from C.
use std::ffi::{CStr, CString};
let c = CString::new("merhaba").unwrap();
let n = unsafe { strlen(c.as_ptr()) }; // 7
let s = CStr::from_bytes_with_nul(b"rust\0").unwrap();
println!("{}", s.to_str().unwrap()); // rustA common mistake: a dangling pointer
The pointer from as_ptr is only valid as long as the CString lives. Taking a pointer from a temporary produces a dangling pointer:
// WRONG: the CString is dropped immediately, p is left invalid
let p = CString::new("x").unwrap().as_ptr();
// RIGHT: bind it to a variable first
let c = CString::new("x").unwrap();
let p = c.as_ptr(); // valid as long as c livesTo hand ownership to C, use into_raw; to take it back, CString::from_raw.
Practice C strings
Declare C's strlen function. Get the length of CString::new("merhaba") with strlen; convert CStr::from_bytes_with_nul(b"rust\0") to a &str; find the result of CString::new("a\0b").is_err(). Print all three separated by spaces.
Starter code
use std::ffi::{c_char, CStr, CString};
fn main() {
// buraya yaz
}Sample solution
use std::ffi::{c_char, CStr, CString};
unsafe extern "C" {
fn strlen(s: *const c_char) -> usize;
}
fn main() {
let c = CString::new("merhaba").unwrap();
// SAFETY: c geçerli, sonu boş baytla biten bir dizedir.
let n = unsafe { strlen(c.as_ptr()) };
let s = CStr::from_bytes_with_nul(b"rust\0").unwrap();
let hata = CString::new("a\0b").is_err();
println!("{} {} {}", n, s.to_str().unwrap(), hata);
}Expected output
7 rust true
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 Why does <code>CString::new("a\0b")</code> error?
- b is invalid
- It's too short
- It doesn't error
- The inner \0 would end the string early on the C side Correct answer
Explanation: If CString::new finds an inner null byte, it returns NulError, preventing silent truncation.
2 Create a C string
let c = ____::new("merhaba").unwrap();
let n = unsafe { strlen(c.as_ptr()) };
let c = CString::new("merhaba").unwrap();
let n = unsafe { strlen(c.as_ptr()) };
Explanation: CString is for sending strings from Rust to C.
3 Type and direction
| Term | Meaning |
|---|---|
CString |
Rust → C (owned) |
CStr |
C → Rust (borrowed) |
as_ptr() |
*const c_char |
into_raw() |
Give ownership to C |