2015-09-25 24 views
0

我有一個場景,我們有一個15年前用C編寫的現有(舊)操作系統。現在,我們正在考慮擴展這個系統,能夠在Rust中編寫用戶空間程序。如何將&str轉換爲* const i8 *而不使用* libstd和libcore?

當然,因爲這是最近開始的,我們並沒有考慮將所有的libstd移植到我們自己的操作系統。因此我們使用#![feature(no_std)]

現在,我正在尋找一些應該合理簡單的東西:將Rust字符串轉換爲C空終止的字符串。應該很簡單,但是因爲我對Rust沒有經驗,所以我還沒有弄清楚。

爲了這個經驗,強加一定的限制就足夠了(比如,最大1024字節長的字符串;其他任何被截斷)。 (我們也有到位的內存分配,但我沒有打擾試圖從防鏽處理內存分配還)

這是迄今爲止我愚蠢的嘗試:

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菲捨爾的答案,我改變了我的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的情況下工作? (無論如何這可能是一個合理的東西......)

回答

4

而不是投射緩衝區,投給緩衝區的引用。 Example

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

您是否嘗試過讓你的代碼與libcore工作?它是標準庫的一個子集,涵蓋了不需要操作系統支持的一切。你可以通過它獲得字符串操作函數。

+3

重要的一點是:因爲'as_ptr'消耗'self',所以會得到代碼進行編譯,但返回值將是一個懸掛指針。 – fjh

+0

哪個as_ptr是?聽起來像是誤會。 – bluss

+0

來自OP的示例代碼的'pub fn as_ptr(self) - > * const i8'。由於它的值是'self',所以'CString'實例將在函數結束時被釋放,這意味着你要返回一個指向釋放內存的指針。 –