![](/img/trans.png)
[英]Conditionally converting the standard output of a Command to a string does not live long enough
[英]Converting output of libc::getcwd into a string
我想打印出libc::getcwd
的結果。 我的問題是創建getcwd
需要一個i8
( c_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.