我有一个场景,大约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
memset
和memcpy
内容很容易修复。我假设的边界检查是在libcore
中实现的 - 没有链接到libcore的任何方式来实现它? (无论如何,这可能是一个合理的事情......)