如何从 &str 转换为 *const i8 *without* libstd 和 libcore?
How to convert from &str to *const i8 *without* libstd and libcore?
我有一个场景,大约 15 年前我们有一个用 C 编写的现有(旧)操作系统。现在,我们正在考虑扩展这个系统,能够用 Rust 编写用户 space 程序。
自然地,因为这是最近才开始的,我们还没有费心将所有 libstd
移植到我们自己的 OS。因此我们使用 #![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()] = '[=10=]' 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
}
代码现在可以编译,但没有 link:
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
中实现的——有什么方法可以在不 link 到 libcore 的情况下使它工作? (无论如何这可能是一件合理的事情......)
我有一个场景,大约 15 年前我们有一个用 C 编写的现有(旧)操作系统。现在,我们正在考虑扩展这个系统,能够用 Rust 编写用户 space 程序。
自然地,因为这是最近才开始的,我们还没有费心将所有 libstd
移植到我们自己的 OS。因此我们使用 #![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()] = '[=10=]' 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
}
代码现在可以编译,但没有 link:
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
中实现的——有什么方法可以在不 link 到 libcore 的情况下使它工作? (无论如何这可能是一件合理的事情......)