如何在不使用* libstd和libcore的情况下将& str转换为* const i8 *?

时间:2015-09-25 16:01:42

标签: string operating-system kernel rust

我有一个场景,大约15年前我们有一个用C语言编写的现有(旧)操作系统。现在,我们正在考虑扩展这个系统,能够在Rust中编写用户空间程序。

当然,因为这是最近开始的,我们还没有把所有libstd移植到我们自己的操作系统上。因此我们使用#![feature(no_std)]

现在,我正在寻找一些相当简单的东西:将Rust字符串转换为C-null终止字符串。应该很简单,但因为我对Rust没有经验,所以我还没有能够解决这个问题。

为了这种体验,它足以施加某些限制(例如,最多1024字节长的字符串;其他任何内容都被截断)。 (我们确实有内存分配,但我还没有尝试处理Rust的内存分配)

到目前为止,这是我的微弱尝试:

pub struct CString {
    buffer: [i8; 1024]
}

impl CString {
    pub fn new(s: &str) -> CString {
        CString {
            buffer: CString::to_c_string(s)
        }
    }

    fn to_c_string(s: &str) -> [i8; 1024] {
        let buffer: [i8; 1024];
        let mut i = 0;

        // TODO: ignore the risk for buffer overruns for now. :)
        // TODO: likewise with UTF8; assume that we are ASCII-only.
        for c in s.chars() {
            buffer[i] = c as i8;
            i = i + 1;
        }

        buffer[s.len()] = '\0' as i8;
        buffer;
    }

    pub fn as_ptr(&self) -> *const i8 {    
        // TODO: Implement. The line below doesn't even compile.
        self.buffer as *const i8
    }
}

这里的核心问题是as_ptr中的类型转换。你怎么在Rust做的?此外,除了显而易见的问题之外,此代码还有其他问题吗? (破解UTF8非ASCII字符处理,如果字符串长度超过1024个字符则完全愚蠢...:)

提前感谢! 必须是相当明显的......

更新:根据Will Fischer的回答(谢谢!),我将as_ptr方法更改为:

pub fn as_ptr(&self) -> *const i8 {
    &self.buffer as *const i8
}

代码现在编译,但它没有链接:

virtio_net_pci.0.rs:(.text._ZN6system8c_string7CString3new20hbfc6c6db748de66bpaaE+0x31): undefined reference to `memset'
virtio_net_pci.0.rs:(.text._ZN6system8c_string7CString3new20hbfc6c6db748de66bpaaE+0x14f): undefined reference to `memcpy'
virtio_net_pci.0.rs:(.text._ZN6system8c_string7CString3new20hbfc6c6db748de66bpaaE+0x174): undefined reference to `panicking::panic_bounds_check::h0b7be17a72a754b5P6E'
virtio_net_pci.0.rs:(.text._ZN6system8c_string7CString3new20hbfc6c6db748de66bpaaE+0x18c): undefined reference to `panicking::panic_bounds_check::h0b7be17a72a754b5P6E'
collect2: error: ld returned 1 exit status

memsetmemcpy内容很容易修复。我假设的边界检查是在libcore中实现的 - 没有链接到libcore的任何方式来实现它? (无论如何,这可能是一个合理的事情......)

1 个答案:

答案 0 :(得分:5)

不是强制转换缓冲区,而是强制转换缓冲区。 Example

fn main() {
    let buffer: [i8; 1024] = [42; 1024];
    let ptr: *const i8 = &buffer as *const i8;
    unsafe {
        println!("{}", *ptr.offset(30));
    }
}

您是否尝试过让代码与libcore一起使用?它是标准库的一个子集,涵盖了不需要OS支持的所有内容。你可以通过它获得字符串操作功能。