将 libc::getcwd 的输出转换为字符串
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
returns NULL(libc::getcwd(...).is_null()
为真),通过外部 crate errno
读取最后一个错误(为什么这是一个单独的 crate to libc ?) 显示 getcwd
失败并显示 "Invalid argument"。问题的根源似乎是 buf.len()
returns 0.
在大多数情况下,您应该只使用env::current_dir
。这会为您正确处理所有特定于平台的问题,例如评论中提到的 "other" 编码。
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);
}
seems that buf.len() returns 0
是的,长度为零,因为没有人告诉矢量数据已添加。矢量由三部分组成 - 指向数据的指针、长度和 容量.
容量是有多少内存可用,大小是使用了多少。将向量视为存储数据的 blob 时,您需要使用容量。然后,您需要通知向量使用了多少字节,以便 String::from_utf8
知道结束位置。
您会注意到我将 unsafe
的范围更改为仅包括真正不安全的方面以及使该代码真正安全的代码。
事实上,您可以直接复制 the implementation of env::current_dir
for Unix-like systems。它更好地处理失败情况并使用正确的类型(路径 不是 字符串)。当然,直接调用 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
,使指针无效。然后 returns 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);
}
I wonder why this has actually worked
可能是因为在您尝试访问内存之前没有任何更改。在高度多线程的环境中,我可以看到更多问题出现。
why is it possible to have two mutable references to the vector? First as mut buf
and then as ptr = buf.as_mut_ptr()
. The ownership has not moved, has it? Otherwise, why is it possible to call buf.capacity()
您实际上没有两个 参考文献。 buf
拥有该值,然后你得到一个 可变指针 。指针没有编译器保护,这是需要 unsafe
块的部分原因
我想打印出 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
returns NULL(libc::getcwd(...).is_null()
为真),通过外部 crate errno
读取最后一个错误(为什么这是一个单独的 crate to libc ?) 显示 getcwd
失败并显示 "Invalid argument"。问题的根源似乎是 buf.len()
returns 0.
在大多数情况下,您应该只使用env::current_dir
。这会为您正确处理所有特定于平台的问题,例如评论中提到的 "other" 编码。
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);
}
seems that buf.len() returns 0
是的,长度为零,因为没有人告诉矢量数据已添加。矢量由三部分组成 - 指向数据的指针、长度和 容量.
容量是有多少内存可用,大小是使用了多少。将向量视为存储数据的 blob 时,您需要使用容量。然后,您需要通知向量使用了多少字节,以便 String::from_utf8
知道结束位置。
您会注意到我将 unsafe
的范围更改为仅包括真正不安全的方面以及使该代码真正安全的代码。
事实上,您可以直接复制 the implementation of env::current_dir
for Unix-like systems。它更好地处理失败情况并使用正确的类型(路径 不是 字符串)。当然,直接调用 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
,使指针无效。然后 returns 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);
}
I wonder why this has actually worked
可能是因为在您尝试访问内存之前没有任何更改。在高度多线程的环境中,我可以看到更多问题出现。
why is it possible to have two mutable references to the vector? First as
mut buf
and then asptr = buf.as_mut_ptr()
. The ownership has not moved, has it? Otherwise, why is it possible to callbuf.capacity()
您实际上没有两个 参考文献。 buf
拥有该值,然后你得到一个 可变指针 。指针没有编译器保护,这是需要 unsafe
块的部分原因