簡體   English   中英

將libc :: getcwd的輸出轉換為字符串

[英]Converting output of libc::getcwd into a string

我想打印出libc::getcwd的結果。 我的問題是創建getcwd需要一個i8c_char )緩沖區,而String::from_utf8需要一個u8緩沖區。 我開始時:

static BUF_BYTES: usize = 4096;

fn main() {
    unsafe {
        let mut buf: Vec<i8> = Vec::with_capacity(BUF_BYTES as usize);
        libc::getcwd(buf.as_mut_ptr(), buf.len());
        let s = String::from_utf8(buf).expect("Found invalid UTF-8");
        println!("result: {}", s);
    }
}

哪會產生錯誤:

14:32 error: mismatched types:
 expected `std::vec::Vec<u8>`,
    found `std::vec::Vec<i8>` [E0308]

感謝評論,我將buf更改為Vec<u8>並將其轉換為getcwd調用中的c_char緩沖區:

    let mut buf: Vec<u8> = Vec::with_capacity(BUF_BYTES as usize);
    libc::getcwd(buf.as_mut_ptr() as *mut c_char, buf.len());

這個編譯但是現在,當打印字符串時它是空的(長度:0)

我發現getcwd返回NULL( libc::getcwd(...).is_null()為true),通過外部crate errno讀取最后一個錯誤(為什么這是一個單獨的crate到libc?)顯示getcwd失敗並顯示“無效”說法”。 問題的根源似乎是buf.len()返回0。

大多數情況下,您應該只使用env::current_dir 這可以正確處理所有特定於平台的內容,例如評論中提到的“其他”編碼。


C弦有點可怕。 getcwd填充一段長度的緩沖區,但不會告訴你它的結束位置; 你必須手動找到終止NUL字節。

extern crate libc;

static BUF_BYTES: usize = 4096;

fn main() {
    let buf = unsafe {
        let mut buf = Vec::with_capacity(BUF_BYTES);
        let res = libc::getcwd(buf.as_mut_ptr() as *mut i8, buf.capacity());
        if res.is_null() {
            panic!("Not long enough");
        }
        let mut len = 0;
        while *buf.as_mut_ptr().offset(len as isize) != 0 { len += 1 }
        buf.set_len(len);
        buf
    };

    let s = String::from_utf8(buf).expect("Found invalid UTF-8");
    println!("result: {}", s);
}

似乎buf.len()返回0

是的,長度為零,因為沒有人告訴向量數據被添加。 向量由三部分組成 - 指向數據的指針,長度和容量

容量是可用的內存量,大小是使用多少。 將矢量視為blob以將數據存儲到其中時,您希望使用該容量。 然后,您需要通知向量使用了多少這些字節,以便String::from_utf8知道結束的位置。

您會注意到我將unsafe的范圍更改為僅包含真正不安全的方面以及使該代碼實際安全的代碼。


實際上,您可以只復制類Unix系統的env::current_dir實現 它更好地處理故障情況並使用正確的類型(路徑不是字符串)。 當然,調用env::current_dir更容易。 ^ _ ^


fyi:我最終得到了這個

 extern crate libc; use std::ffi::CStr; use std::io; use std::str; static BUF_BYTES: usize = 4096; fn main() { let buf = unsafe { let mut buf = Vec::with_capacity(BUF_BYTES); let ptr = buf.as_mut_ptr() as *mut libc::c_char; if libc::getcwd(ptr, buf.capacity()).is_null() { panic!(io::Error::last_os_error()); } CStr::from_ptr(ptr).to_bytes() }; println!("result: {}", str::from_utf8(buf).unwrap()); } 

這是不安全的 ,會導致崩潰(在最好的情況下)或無聲的內存損壞或更糟。

當塊結束時,其中的任何變量都將被刪除。 在這種情況下, unsafe塊創建buf ,獲取指向它的指針,使用指針創建CStr ,然后釋放Vec ,使指針無效。 然后它返回包含來自塊的無效引用的CStr

這樣的事情更好:

extern crate libc;

use std::ffi::{CStr, CString};
use std::io;
use std::str;

static BUF_BYTES: usize = 4096;

fn main() {
    let buf = unsafe {
        // Allocate some space to store the result
        let mut buf = Vec::with_capacity(BUF_BYTES);

        // Call the function, panicking if it fails
        let ptr = buf.as_mut_ptr() as *mut libc::c_char;
        if libc::getcwd(ptr, buf.capacity()).is_null() {
            panic!(io::Error::last_os_error());
        }

        // Find the first NUL and inform the vector of that
        let s = CStr::from_ptr(ptr);
        buf.set_len(s.to_bytes().len());

        // Transfer ownership of the Vec to a CString, ensuring there are no interior NULs
        CString::new(buf)
    };

    let s = buf.expect("Not a C string").into_string().expect("Not UTF-8");
    println!("result: {}", s);
}

我想知道為什么這實際上有效

可能因為在您嘗試訪問它之前沒有改變內存。 在一個繁重的多線程環境中,我可以看到更多的問題。

為什么有可能對載體有兩個可變引用? 首先作為mut buf然后作為ptr = buf.as_mut_ptr() 所有權沒有動,是嗎? 否則,為什么可以調用buf.capacity()

你實際上沒有兩個引用 buf擁有該值,然后你得到一個可變指針 指針沒有編譯器保護,這是需要unsafe塊的部分原因

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM