pub struct CString { /* private fields */ }
Expand description
一种类型,表示拥有的,C 兼容的,以 nul 终止的字符串,中间没有 nul 字节。
此类型的目的是能够从 Rust 字节切片或 vector 安全地生成 C 兼容字符串。
此类型的一个实例是静态保证,底层字节不包含内部 0 字节 (nul 字符
),并且最后一个字节为 0 (nul 终止符
)。
CString
到 &CStr
如同 String
到 &str
: 每对中的前者是拥有所有权的字符串; 后者是借用的。
创建一个 CString
CString
是从字节切片、字节 vector 或任何实现 Into<Vec<u8>>
创建的 (例如,您可以直接从 String
或 &str
,因为两者都实现了该 trait)。
CString::new
方法实际上会检查提供的 &[u8]
中是否没有 0 个字节,如果找到一个,将返回一个错误。
将裸指针提取到整个 C 字符串
CString
通过 Deref
trait 实现了一个 as_ptr
方法。此方法将为您提供 *const c_char
,您可以直接将其输入期望包含以 N 结束的字符串的 extern 函数,例如 C 的 strdup()
。
注意,as_ptr
返回一个只读指针。如果 C 代码写入它,则会导致未定义的行为。
提取整个 C 字符串的切片
或者,您可以使用 CString::as_bytes
方法从 CString
获取 &[u8]
切片。以这种方式产生的切片不包含尾随 nul 终止符。
当您要调用带有 *const u8
参数 (不一定是 nul 终止) 的 extern 函数,以及带有字符串长度的另一个参数 (如 C 的 strndup()
) 时,此功能很有用。
当然,您可以使用 len
方法获取切片的长度。
如果您需要一个带 nul 终止符的 &[u8]
切片,您可以使用 CString::as_bytes_with_nul
代替。
一旦有了所需的切片类型 (带或不带 nul 终止符),就可以调用切片自己的 as_ptr
方法来获取只读的裸指针,以将其传递给 extern 函数。
有关确保裸指针的生命周期的讨论,请参见该函数的文档。
Examples
use std::ffi::CString;
use std::os::raw::c_char;
extern "C" {
fn my_printer(s: *const c_char);
}
// 我们确定我们的字符串中间没有 0 个字节,因此我们可以 .expect()
let c_to_print = CString::new("Hello, world!").expect("CString::new failed");
unsafe {
my_printer(c_to_print.as_ptr());
}
RunSafety
CString
旨在处理传统的 C 样式字符串 (由单个空字节终止的非空字节序列) ; 这些类型的字符串的主要用例是与类似 C 的代码进行互操作。
通常,您将需要转让该外部代码的所有权 to/from。
强烈建议您在使用 CString
之前通读 CString
文档,因为对 CString
实例的所有权管理不当会导致无效的内存访问,内存泄漏和其他内存错误。
Implementations§
source§impl CString
impl CString
1.0.0 · sourcepub fn new<T>(t: T) -> Result<CString, NulError>where
T: Into<Vec<u8, Global>>,
pub fn new<T>(t: T) -> Result<CString, NulError>where T: Into<Vec<u8, Global>>,
从字节容器创建一个新的 C 兼容字符串。
此函数将消费提供的数据,并使用底层字节构建新的字符串,从而确保有一个尾随的 0 字节。
这个函数将追加这个尾随的 0 字节; 提供的数据不应包含任何 0 字节。
Examples
use std::ffi::CString;
use std::os::raw::c_char;
extern "C" { fn puts(s: *const c_char); }
let to_print = CString::new("Hello!").expect("CString::new failed");
unsafe {
puts(to_print.as_ptr());
}
RunErrors
如果提供的字节包含内部 0 字节,则此函数将返回错误。
返回的 NulError
将包含字节以及 nul 字节的位置。
1.0.0 · sourcepub unsafe fn from_vec_unchecked(v: Vec<u8, Global>) -> CString
pub unsafe fn from_vec_unchecked(v: Vec<u8, Global>) -> CString
通过使用字节 vector 来创建 C 兼容字符串,而无需检查内部 0 字节。
该函数将追加尾随的 0 字节。
此方法等效于 CString::new
,除了不进行运行时断言,即 v
不包含 0 字节,并且它需要实际的字节 vector,而不是可以使用 Into 转换为 1 的任何内容。
Examples
use std::ffi::CString;
let raw = b"foo".to_vec();
unsafe {
let c_string = CString::from_vec_unchecked(raw);
}
Run1.4.0 · sourcepub unsafe fn from_raw(ptr: *mut i8) -> CString
pub unsafe fn from_raw(ptr: *mut i8) -> CString
重新获得通过 CString::into_raw
转移到 C 的 CString
的所有权。
此外,将根据指针重新计算字符串的长度。
Safety
仅应使用先前通过调用 CString::into_raw
获得的指针进行调用。
其他用法 (例如,尝试获取由外部代码分配的字符串的所有权) 可能导致未定义的行为或分配器损坏。
应该注意的是,长度不仅是 “recomputed,”,而且重新计算的长度必须与 CString::into_raw
调用的原始长度匹配。
这意味着在将字符串传递到可以修改字符串长度的 C 函数时,不应使用 CString::into_raw
/from_raw
方法。
Note: 如果您需要借用由分配的字符串 外部代码,请使用
CStr
。如果您需要获得所有权从 由外部代码分配的字符串,您将需要 制定自己的规定以适当地,可能地释放它 使用外部代码的 API 来做到这一点。
Examples
创建一个 CString
,将所有权传递给 extern
函数 (通过裸指针),然后使用 from_raw
重新获得所有权:
1.4.0 · sourcepub fn into_raw(self) -> *mut i8
pub fn into_raw(self) -> *mut i8
消耗 CString
,并将字符串的所有权转让给 C 调用者。
此函数返回的指针必须返回到 Rust,并使用 CString::from_raw
进行重构以正确释放。
具体来说,应该 不要 使用标准的 C free()
函数来释放该字符串。
未能调用 CString::from_raw
将导致内存泄漏。
C 端必须不修改字符串的长度 (通过在字符串内某处写入 null
或删除最后一个),然后使用 CString::from_raw
将其返回到 Rust。
请参见 CString::from_raw
中的安全性部分。
Examples
use std::ffi::CString;
let c_string = CString::new("foo").expect("CString::new failed");
let ptr = c_string.into_raw();
unsafe {
assert_eq!(b'f', *ptr as u8);
assert_eq!(b'o', *ptr.add(1) as u8);
assert_eq!(b'o', *ptr.add(2) as u8);
assert_eq!(b'\0', *ptr.add(3) as u8);
// 重新获得指向空闲内存的指针
let _ = CString::from_raw(ptr);
}
Run1.7.0 · sourcepub fn into_string(self) -> Result<String, IntoStringError>
pub fn into_string(self) -> Result<String, IntoStringError>
如果 CString
包含有效的 UTF-8 数据,则将其转换为 String
。
失败时,将返回原始 CString
的所有权。
Examples
use std::ffi::CString;
let valid_utf8 = vec![b'f', b'o', b'o'];
let cstring = CString::new(valid_utf8).expect("CString::new failed");
assert_eq!(cstring.into_string().expect("into_string() call failed"), "foo");
let invalid_utf8 = vec![b'f', 0xff, b'o', b'o'];
let cstring = CString::new(invalid_utf8).expect("CString::new failed");
let err = cstring.into_string().err().expect("into_string().err() failed");
assert_eq!(err.utf8_error().valid_up_to(), 1);
Run1.7.0 · sourcepub fn into_bytes_with_nul(self) -> Vec<u8, Global> ⓘ
pub fn into_bytes_with_nul(self) -> Vec<u8, Global> ⓘ
等效于 CString::into_bytes()
,除了返回的 vector 包括结尾的 nul 终止符。
Examples
use std::ffi::CString;
let c_string = CString::new("foo").expect("CString::new failed");
let bytes = c_string.into_bytes_with_nul();
assert_eq!(bytes, vec![b'f', b'o', b'o', b'\0']);
Run1.0.0 · sourcepub fn as_bytes(&self) -> &[u8] ⓘ
pub fn as_bytes(&self) -> &[u8] ⓘ
以字节片形式返回此 CString
的内容。
返回的切片不包含尾随 nul 终止符,并且保证不包含任何内部 nul 字节。
如果需要 nul 终止符,请改用 CString::as_bytes_with_nul
。
Examples
use std::ffi::CString;
let c_string = CString::new("foo").expect("CString::new failed");
let bytes = c_string.as_bytes();
assert_eq!(bytes, &[b'f', b'o', b'o']);
Run1.0.0 · sourcepub fn as_bytes_with_nul(&self) -> &[u8] ⓘ
pub fn as_bytes_with_nul(&self) -> &[u8] ⓘ
等效于 CString::as_bytes()
,但返回的切片包括结尾的 nul 终止符。
Examples
use std::ffi::CString;
let c_string = CString::new("foo").expect("CString::new failed");
let bytes = c_string.as_bytes_with_nul();
assert_eq!(bytes, &[b'f', b'o', b'o', b'\0']);
Run1.20.0 · sourcepub fn into_boxed_c_str(self) -> Box<CStr, Global>
pub fn into_boxed_c_str(self) -> Box<CStr, Global>
1.58.0 · sourcepub fn from_vec_with_nul(
v: Vec<u8, Global>
) -> Result<CString, FromVecWithNulError>
pub fn from_vec_with_nul( v: Vec<u8, Global> ) -> Result<CString, FromVecWithNulError>
存在运行时检查以确保 Vec
(它的最后一个元素) 中只有一个 nul 字节。
Errors
如果存在 nul 字节而不是最后一个元素,或者不存在 nul 字节,则将返回错误。
Examples
如果调用成功而没有结尾的 nul 字节,则转换将产生与 CString::new
相同的结果。
use std::ffi::CString;
assert_eq!(
CString::from_vec_with_nul(b"abc\0".to_vec())
.expect("CString::from_vec_with_nul failed"),
CString::new(b"abc".to_vec()).expect("CString::new failed")
);
Run格式不正确的 Vec
会产生错误。
use std::ffi::{CString, FromVecWithNulError};
// 内部 nul 字节
let _: FromVecWithNulError = CString::from_vec_with_nul(b"a\0bc".to_vec()).unwrap_err();
// 无空字节
let _: FromVecWithNulError = CString::from_vec_with_nul(b"abc".to_vec()).unwrap_err();
RunMethods from Deref<Target = CStr>§
1.0.0 · sourcepub fn as_ptr(&self) -> *const i8
pub fn as_ptr(&self) -> *const i8
返回此 C 字符串的内部指针。
返回的指针在 self
内一直有效,并且指向以 0 字节结尾的连续区域,以表示字符串的结尾。
返回指针的类型是 *const c_char
,它是 *const i8
还是 *const u8
的别名是平台特定的。
WARNING
返回的指针是只读的; 对其进行写入 (包括将其传递给进行写入的 C 代码) 会导致未定义的行为。
您有责任确保底层内存不会过早释放。例如,当在 unsafe
块中使用 ptr
时,以下代码将导致未定义的行为:
use std::ffi::CString;
// 不要这样做:
let ptr = CString::new("Hello").expect("CString::new failed").as_ptr();
unsafe {
// `ptr` 是悬垂的
*ptr;
}
Run发生这种情况是因为 as_ptr
返回的指针不携带任何生命周期信息,并且 CString
在 CString::new("Hello").expect("CString::new failed").as_ptr()
表达式计算后立即被释放。
要解决此问题,请将 CString
绑定到本地变量:
use std::ffi::CString;
let hello = CString::new("Hello").expect("CString::new failed");
let ptr = hello.as_ptr();
unsafe {
// `ptr` 有效,因为 `hello` 在作用域内
*ptr;
}
Run这样,hello
中 CString
的生命周期就包含了 ptr
和 unsafe
区块的生命周期。
1.0.0 · sourcepub fn to_bytes_with_nul(&self) -> &[u8] ⓘ
pub fn to_bytes_with_nul(&self) -> &[u8] ⓘ
将此 C 字符串转换为包含尾随 0 字节的字节切片。
此函数与 CStr::to_bytes
等效,除了保留尾随的 nul 终止符而不是将其截断之外。
Note: 目前,此方法已实现为零费用强制转换,但是 计划在 future 中更改其定义以执行 每次调用此方法时的长度计算。
Examples
use std::ffi::CStr;
let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
assert_eq!(cstr.to_bytes_with_nul(), b"foo\0");
Run1.4.0 · sourcepub fn to_string_lossy(&self) -> Cow<'_, str>
pub fn to_string_lossy(&self) -> Cow<'_, str>
如果 CStr
的内容是有效的 UTF-8 数据,该函数将返回一个 Cow::Borrowed(&str)
和相应的 &str
切片。
否则,它将用 U+FFFD 替换字符
替换任何无效的 UTF-8 序列,并返回 Cow::Owned(&str)
作为结果。
Examples
在包含有效 UTF-8 的 CStr
上调用 to_string_lossy
:
use std::borrow::Cow;
use std::ffi::CStr;
let cstr = CStr::from_bytes_with_nul(b"Hello World\0")
.expect("CStr::from_bytes_with_nul failed");
assert_eq!(cstr.to_string_lossy(), Cow::Borrowed("Hello World"));
Run在包含无效 UTF-8 的 CStr
上调用 to_string_lossy
:
use std::borrow::Cow;
use std::ffi::CStr;
let cstr = CStr::from_bytes_with_nul(b"Hello \xF0\x90\x80World\0")
.expect("CStr::from_bytes_with_nul failed");
assert_eq!(
cstr.to_string_lossy(),
Cow::Owned(String::from("Hello �World")) as Cow<'_, str>
);
Run