我在标准库中没有找到任何关于如何生成const &'static CStr
的内容。我尝试自己编写宏来将&'static str
转换为&'static CStr
:
macro_rules! cstr {
($e: expr) => {{
const buffer: &str = concat!($e, "\0");
unsafe {std::ffi::CStr::from_bytes_with_nul_unchecked(buffer.as_bytes())}
}}
}
字符串
它有几个问题:
1.如果expr
包含空字节,则调用未定义行为
str::as_bytes
不是const
,所以&CStr
不是const
4条答案
按热度按时间cqoc49vn1#
Rust 1.46.0(撰写本文时的当前beta工具链)这是可能的,因为
std::mem::transmute
已经稳定为const fn
。您还可以使用const fn
s检查字符串的内容是否有效(即没有空字节),因为你也可以使用基本的条件表达式和循环。通过panic!
恐慌在常量上下文中还不可能,但是你可以使用隐式恐慌代码(例如[][0]
)来在编译时引发错误。总而言之,这里有一个功能齐全的例子,它只使用const fn
s和声明性宏来允许在常量上下文中创建&'static CStr
s,包括检查内容中是否有非法的空字节。字符串
请注意,这确实依赖于
CStr
的实现细节(特别是布局与[u8]
兼容),因此不应在生产代码中使用。bqujaahr2#
有一个crate,byte_strings。总结一下crate,基本思想是使用一个union,其中有一个
&'static [u8]
(或&'static str
)成员和一个&'static CStr
成员:字符串
由于构造union是
const
,访问const
union的字段也是const
,因此阅读dst
实际上是const
的转换。由于CStr
目前只是[c_char]
的 Package 器,因此&[u8]
可以安全地截断为&CStr
,但是,在将来,CStr
s的表示可能会改变。您可以通过使用零大小数组长度的小技巧来检查&CStr
与&[u8]
的大小是否相同:型
如果它们的大小不一样,Rust的类型检查器会抱怨。将它们放在一起,您可以创建一个宏来生成
const &'static CStr
:型
不幸的是,这个宏仍然不安全,因为它不检查
&str
切片中的空字节,这只能用过程宏来完成。byte_strings crate包含这样一个宏,以及用于连接字节字符串的宏和其他方便的宏。dtcbnfnu3#
一个
CStr
是一个borrowed type,因此,它不是“独立”生成的。在底层,它只不过是一个CString
的引用,可以从以下两种方式中创建:CString
(显而易见)。原始(源)CString
不能被删除,CStr
的生存期仅在源存在时有效CStr::from_bytes_with_nul
从一个字节切片中提取。CStr
仅在原始切片中有效(原始切片本身仅在源数据分配 * 某处 * 时有效)通过
CString
创建CStr
很简单:字符串
转换现有切片也很简单:
型
请注意,这些文件的生存期显然取决于您用来创建
&CStr
的任何文件的生存期,如其声明中的lifetime参数所示留给后人:
'static
不是硬性要求要创建一个
const &'static CStr
,你会很困难,你需要一个外部的crate来创建一个特定的宏(lazy_static
),但这是可行的,就像这样:型
lazy_static
的要点是在定义静态引用时允许函数调用;我们可以利用这一点来动态地构建CStr
,由于它是一个静态引用,因此借用它对于'static
(包括'static
)都是有效的。使命完成。ig9co6j14#
在2021版及以后版本的夜间(计划为1.76.0,将于2024年2月8日发布),您可以使用
c
前缀创建&CStr
文字:字符串
这允许使用转义(甚至非UTF-8),检查内部NUL字节(并拒绝它们),并正确添加尾随NUL。
在旧版本中,您可以使用
cstr
crate:型