В большинстве случаев вам следует просто использовать 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
Да, длина равна нулю, потому что вектору никто не сказал, что данные добавлены. Векторы состоят из трех частей: указателя на данные, длины и емкости.
Емкость — это объем доступной памяти, размер — сколько используется. При обработке вектора как большого двоичного объекта для хранения данных вы хотите использовать емкость. Затем вам нужно сообщить вектору, сколько из этих байтов было использовано, чтобы String::from_utf8
знал, где конец.
Вы заметите, что я изменил область unsafe
, чтобы включить только действительно небезопасные аспекты и код, который делает этот код действительно безопасным.
Фактически, вы можете просто скопировать реализация env::current_dir
для Unix-подобных систем. Он гораздо лучше обрабатывает случаи сбоев и использует правильные типы (пути не являются строками). Конечно, еще проще просто позвонить env::current_dir
. ^_^
к вашему сведению: я закончил с этим
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
.
person
Shepmaster
schedule
05.07.2016
buf
Vec<u8>
, а затем вызватьlibc::getcwd(buf.as_mut_ptr() as *mut i8, buf.len())
. Или что-то вроде того. - person pyon   schedule 05.07.2016getcwd
будет закодирован в UTF-8, вы можете заглянуть вOsString
, который специально предназначен для их содержания. - person Matthieu M.   schedule 05.07.2016as *mut c_char
на случай, еслиc_char
когда-либо изменится. - person Matthieu M.   schedule 05.07.2016i8
будет правильным типом при любых обстоятельствах, а вы справедливо указываете, что это не обязательно. - person pyon   schedule 05.07.2016OsString
не имеет нет неотъемлемого отношения к строкам C. Например, в WindowsOsString
— это WTF-8, в то время как строки C гарантировано находятся в какой-то другой кодировке (поскольку Win32 не знает, что такое WTF-8) . - person DK.   schedule 05.07.2016