rust - 有什么方法可以创建 const &'static CStr 吗?

标签 rust ffi

我没有在标准库中找到任何关于如何制作 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 包含一个空字节,它会调用未定义的行为
  2. str::as_bytes 不是 const,所以 &CStr 不是 const

最佳答案

从 Rust 1.46.0(撰写本文时的当前 beta 工具链)开始,这是可能的,因为 std::mem::transmute 作为 const fn 是稳定的>。您还可以使用 const fn 来检查字符串的内容是否有效(即没有空字节),因为您也可以使用基本的条件表达式和循环。通过 panic! 进行 panic 在常量上下文中尚不可行,但您可以使用隐式 panic 代码(例如 [][0])在编译时引发错误。总而言之,这是一个功能齐全的示例,它仅使用 const fn 和声明性宏来允许在常量上下文中创建 &'static CStr,包括检查内容是否非法空字节。

#[allow(unconditional_panic)]
const fn illegal_null_in_string() {
    [][0]
}

#[doc(hidden)]
pub const fn validate_cstr_contents(bytes: &[u8]) {
    let mut i = 0;
    while i < bytes.len() {
        if bytes[i] == b'\0' {
            illegal_null_in_string();
        }
        i += 1;
    }
}

macro_rules! cstr {
    ( $s:literal ) => {{
        $crate::validate_cstr_contents($s.as_bytes());
        unsafe { std::mem::transmute::<_, &std::ffi::CStr>(concat!($s, "\0")) }
    }};
}

const VALID: &std::ffi::CStr = cstr!("hello world");
// const INVALID: &std::ffi::CStr = cstr!("hello\0world");

fn main() {
    println!("Output: {:?}", VALID);
}

请注意,这确实依赖于 CStr 的实现细节(特别是布局与 [u8] 兼容),因此不应在生产代码中使用.

关于rust - 有什么方法可以创建 const &'static CStr 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58349489/

相关文章:

c - Haskell 外来类型的惯用用法?

rust - 允许函数接受 `T` 或任何 `FnMut(T) -> T`

rust - 具有内部可变性的细胞,允许任意突变 Action

ffi - 如何在 PureScript FFI 中映射 0 参数 JavaScript 函数

c - 如何从 Rust 库访问全局 C 结构数组?

c - 如何在没有 c2hs 或其他工具的情况下为此结构创建可存储实例?

mocha.js - PureScript FFI 转 mocha

rust - 语法: 'let secretbox::Key(ref mut kb) = k;' 的解释

rust - 我如何告诉 Cargo 构建 main.rs 以外的文件?

reference - 将 &T 的迭代器收集到 T 集合中的惯用方法是什么?