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

时间:2016-07-05 06:17:39

标签: rust libc

我想打印出 feedItems.addAll(adItems);//you are set adItems in wrong arraylist (feedItems is a feetItem array list not a adItem list) public FeedRecyclerAdapter(Context context, List<Feed> feedItems, ImageLoader feedItemImageLoader, List<Object> adItems) { this.context = context; this.feedItems = feedItems; this.feedItemImageLoader = feedItemImageLoader; feedItems.addAll(adItems); }` 的结果。我的问题是创建libc::getcwd需要getcwdi8)缓冲区,而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>来电中的c_char缓冲区:

getcwd

这会编译,但现在,当打印字符串时,它是空的(长度:0)

我发现 let mut buf: Vec<u8> = Vec::with_capacity(BUF_BYTES as usize); libc::getcwd(buf.as_mut_ptr() as *mut c_char, buf.len()); 返回NULL(getcwd为真),通过外部包libc::getcwd(...).is_null()读取最后一个错误(为什么这是一个单独的包给libc?)显示{{ 1}}失败并显示“无效参数”。问题的根源似乎是errno返回0。

1 个答案:

答案 0 :(得分:3)

大多数情况下,您应该只使用env::current_dir。这正确地为您处理所有特定于平台的内容,例如&#34;其他&#34;评论中提到的编码。

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的范围更改为仅包含真正不安全的方面以及使该代码实际安全的代码。

事实上,你可以复制the implementation of env::current_dir for Unix-like systems。它可以更好地处理故障情况并使用正确的类型(路径不是字符串)。当然,只需拨打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块的部分原因