首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将数据分配给FFI调用的正确方法是什么?

将数据分配给FFI调用的正确方法是什么?
EN

Stack Overflow用户
提问于 2016-09-17 19:24:58
回答 1查看 2.6K关注 0票数 5

discussing/learning about the correct way to call a FFI of the Windows-API from Rust之后,我玩得更远了一点,我想再检查一下我的理解。

我有一个被调用两次的Windows。在第一个调用中,它返回实际out参数所需的缓冲区大小。然后,它被称为第二次具有足够大小的缓冲区。我目前正在使用Vec作为此缓冲区的数据类型(参见下面的示例)。

代码可以工作,但我想知道这是否是正确的方法,或者使用像alloc::heap::allocate这样的函数直接保留一些内存,然后使用transmute将结果转换回FFI是否更好。同样,我的代码可以工作,但我试图在幕后稍微看一看。

代码语言:javascript
复制
extern crate advapi32;
extern crate winapi;
extern crate widestring;
use widestring::WideCString;
use std::io::Error as IOError;
use winapi::winnt;

fn main() {
    let mut lp_buffer: Vec<winnt::WCHAR> = Vec::new();
    let mut pcb_buffer: winapi::DWORD = 0;

    let rtrn_bool = unsafe {
        advapi32::GetUserNameW(lp_buffer.as_mut_ptr(),
                               &mut pcb_buffer )
    };

    if rtrn_bool == 0 {

        match IOError::last_os_error().raw_os_error() {
            Some(122) => {
                // Resizing the buffers sizes so that the data fits in after 2nd 
                lp_buffer.resize(pcb_buffer as usize, 0 as winnt::WCHAR);
            } // This error is to be expected
            Some(e) => panic!("Unknown OS error {}", e),
            None => panic!("That should not happen"),
        }
    }


    let rtrn_bool2 = unsafe {
        advapi32::GetUserNameW(lp_buffer.as_mut_ptr(), 
                               &mut pcb_buffer )
    };

    if rtrn_bool2 == 0 {
        match IOError::last_os_error().raw_os_error() {
            Some(e) => panic!("Unknown OS error {}", e),
            None => panic!("That should not happen"),
        }
    }

    let widestr: WideCString = unsafe { WideCString::from_ptr_str(lp_buffer.as_ptr()) };

    println!("The owner of the file is {:?}", widestr.to_string_lossy());
}

依赖关系:

代码语言:javascript
复制
[dependencies]
advapi32-sys = "0.2"
winapi = "0.2"
widestring = "*"
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-09-17 20:09:43

理想情况下,您可以使用std::alloc::alloc,因为您可以指定所需的对齐作为布局的一部分。

代码语言:javascript
复制
pub unsafe fn alloc(layout: Layout) -> *mut u8

主要的缺点是,您需要知道对齐,即使当您释放分配。

使用Vec作为一种简单的分配机制是一种常见的做法,但您在使用它时需要小心。

  1. 确保你的单位是正确的-“长度”参数是项目数还是字节数?
  2. 如果将Vec分解成组件,则需要。
    1. 跟踪长度和容量。有些人使用shrink_to_fit来确保这两个值是相同的。
    2. 避免横越流--内存是由Rust分配的,必须释放。将其转换回要删除的Vec

  1. 注意,一个空的Vec而不是有一个空指针!: fn main() { let v: Vec = Vec::new();println!("{:p}",v.as_ptr());// => 0x1 }

对于您的具体情况,我可能建议使用capacity of Vec而不是自己跟踪第二个变量。您将注意到在第一个调用之后忘记更新pcb_buffer,所以我非常肯定代码总是失败的。这很烦人,因为它需要一个可变的引用,所以你不能完全摆脱它。

此外,您可以只使用extend空间,而不是Vec中的reserve

也不能保证第一次调用期间所需的大小将与第二次调用期间所需的大小相同。你可以做一些循环,但你必须担心无限循环的发生。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39550856

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档