在大多数情况下,你应该只使用
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。
是的,长度为0,因为没有人告诉向量添加了数据。向量由三个部分组成-指向数据的指针、长度和容量。
容量是可用内存大小,尺寸是使用了多少。当将向量视为存储数据的 blob 时,应使用容量。然后您需要告知向量使用了多少字节,以便
String::from_utf8
知道其结尾在哪里。
请注意,我将
unsafe
的范围更改为仅包括真正不安全的方面和使该代码实际上安全的代码。
实际上,你可以直接复制
Unix-like 系统下 env::current_dir
的实现。它更好地处理了失败情况并使用了正确的类型(路径
不是字符串)。当然,更容易的方法是直接调用
env::current_dir
。^_^
fyi: I ended up with this
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 {
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());
}
let s = CStr::from_ptr(ptr);
buf.set_len(s.to_bytes().len());
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
块的原因之一。
buf
定义为Vec<u8>
,然后调用libc::getcwd(buf.as_mut_ptr() as *mut i8, buf.len())
。或者类似的操作。 - isekaijingetcwd
的结果编码为UTF-8,你可能需要了解一下OsString
,它专门用于包含这些内容。 - Matthieu M.c_char
有所更改,最好使用as *mut c_char
。 - Matthieu M.i8
在所有情况下都是正确的类型,但你指出它不必如此。 - isekaijinOsString
与C字符串没有固有的关系。例如,在Windows上,OsString
是WTF-8,而C字符串保证以某种其他编码存在(因为Win32不知道WTF-8是什么)。 - DK.