Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby-on-rails-4/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Rust 将libc::getcwd的输出转换为字符串_Rust_Libc - Fatal编程技术网

Rust 将libc::getcwd的输出转换为字符串

Rust 将libc::getcwd的输出转换为字符串,rust,libc,Rust,Libc,我想打印出libc::getcwd的结果。我的问题是创建getcwd需要i8(c\u 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

我想打印出
libc::getcwd
的结果。我的问题是创建
getcwd
需要
i8
c\u 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);
    }
}
这会编译,但现在打印字符串时它是空的(长度:0)


我发现
getcwd
返回NULL(
libc::getcwd(…)。is_NULL()
为true),通过外部板条箱
errno
读取最后一个错误(为什么这是libc的单独板条箱?)显示
getcwd
因“无效参数”而失败。问题的根源似乎是
buf.len()
返回0。

大多数情况下,您应该使用。这将正确地为您处理所有平台细节,例如注释中提到的“其他”编码


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
的范围,只包括真正不安全的方面和使代码真正安全的代码


事实上,你可以复制。它可以更好地处理故障情况,并使用适当的类型(路径不是字符串)。当然,只需调用
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);
}

我想知道为什么这真的有效

可能是因为在您尝试访问内存之前,内存没有发生任何更改。在一个高度多线程的环境中,我可以看到更多的问题出现

为什么可能有两个可变的向量引用?首先是as
mut buf
,然后是as
ptr=buf.as\u mut\u ptr()
。所有权没有转移,是吗?否则,为什么可以调用
buf.capacity()


你实际上没有两个推荐人
buf
拥有该值,然后您将得到一个可变指针。指针没有编译器保护,这是需要
unsafe
块的部分原因

您可以将
buf
a
Vec
,然后调用
libc::getcwd(buf.as_mut_ptr()as*mut i8,buf.len())
。或者类似的东西。注意:不能保证
getcwd
的结果将被编码为UTF-8,您可能需要查看
OsString
,它是专门用来包含这些内容的。@pyon:如果
c\u char
发生任何变化,最好使用
作为*mut c\u char
。@MatthieuM。是的,你说得对。我只是看了一下代码片段,并假设
i8
在任何情况下都是正确的类型,而您正确地指出它不需要。@MatthieuM
OsString
与C字符串没有固有的关系。例如,在Windows上,
OsString
是WTF-8,而C字符串则保证采用其他编码(因为Win32不知道WTF-8是什么)。非常感谢您花时间编写这一详尽的答案。我对生锈和操作系统编程都是新手,所以这给了我一些未来很有价值的建议。是的,我可以使用
env::current_dir
,但我正试图尽可能接近Unix编程。@PhilippKeller它是“Unix编程”->请参阅及其。不要认为Rust有一个很好的接口,它在做一些无聊的事情。我正在阅读“Unix环境中的高级编程”,这是对“C中的Unix编程”的指导性参考,包括所有函数定义和内存结构。这就是为什么我现在想继续使用以null结尾的字符串和所有这些“障碍”。感谢您的提示,
std::env::current_dir
fyi:I中的实际实现以这样的方式结束:-CStr有一个
from_ptr
函数,它将
NUL
终止的字符串转换为数组。此外,io具有
io::Error::last_os_Error
,因此外部
errno
板条箱不可用needed@PhilippKeller看我的更新,讨论为什么这是个坏主意。
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());
}
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);
}