C 转 Rust
基本思路是:
(1) char* ----> *c_char:C 语言的字符串 char* 转换到 Rust,最直接的 Rust 类型是 *c_char。这样总算把 C 语言的字符串用 Rust 表示出来了,当然 c_char 并不是 Rust 中内置的数据类型,所以好需要继续做转换。
(2) *c_char ----> &CStr:把以 \0 结束的字符串封装成 Rust 的胖指针,在单纯的指针上面添加了长度信息。也就是说,CStr 把 C 字符串转化成了 Rust 的数组。
(3) &CStr ----> &str:这就彻底变成 Rust 里正宗的字符串了,只不过现在还是只读的。如果要修改,需要进一步变成 Rust 的 String 类型。
具体参见下面的代码。
extern crate libc;use libc::c_char;
use std::ffi::CStr;
use std::str;extern {fn hello() -> *const c_char;
}fn main() {let c_buf: *const c_char = unsafe { hello() };let c_str: &CStr = unsafe { CStr::from_ptr(c_buf) };let str_slice: &str = c_str.to_str().unwrap();let str_buf: String = str_slice.to_owned(); // if necessary
}
Rust 转 C
基本步骤如下:
(1) 首先可以用很多办法把 Rust 的字符传转换成 CString 类型。 CString 类型很有意思,它用 \0 中止字符串。这样,字符串的结构和 C 语言基本一致了。
(2) CString ----> CStr,这个办法也很多,具体看代码吧。
extern crate libc;use libc::c_char;
use std::ffi::CString;fn main() {let c_str_1 = CString::new("hello").unwrap(); // from a &str, creates a new allocationlet c_str_2 = CString::new(b"world" as &[u8]).unwrap(); // from a &[u8], creates a new allocationlet data: Vec<u8> = b"12345678".to_vec(); // from a Vec<u8>, consumes itlet c_str_3 = CString::new(data).unwrap();// and now you can obtain a pointer to a valid zero-terminated string// make sure you don't use it after c_str_2 is droppedlet c_ptr: *const c_char = c_str_2.as_ptr();// the following will print an error message because the source data// contains zero byteslet data: Vec<u8> = vec![1, 2, 3, 0, 4, 5, 0, 6];match CString::new(data) {Ok(c_str_4) => println!("Got a C string: {:p}", c_str_4.as_ptr()),Err(e) => println!("Error getting a C string: {}", e),}
}
参考资料
- songroom:如何将C字符串转换为Rust字符串并通过FFI返回?