How do I initialize an opaque C struct when using Rust FFI?

家住魔仙堡 提交于 2019-12-05 03:29:10
Shepmaster

The safest answer is to initialize the struct yourself:

let mut x: some_lib_struct_t = some_lib_struct_t;
unsafe {
    some_lib_func(&mut x);
}

The closest analog to the C code is to use mem::uninitialized:

unsafe {
    let mut x: some_lib_struct_t = std::mem::uninitialized();
    some_lib_func(&mut x);
}

You have to be sure that some_lib_func completely initializes all the members of the struct, otherwise the unsafety will leak outside of the unsafe block.

Speaking of "members of the struct", I can almost guarantee your code won't do what you want. You've defined some_lib_struct_t as having zero size. That means that no stack space will be allocated for it, and a reference to it won't be what your C code is expecting.

You need to mirror the definition of the C struct in Rust so that the appropriate size, padding, and alignment can be allocated. Usually, this means using repr(C).

Many times, C libraries avoid exposing their internal struct representation by always returning a pointer to the opaque type:

After reading Shepmaster's answer, I looked closer at the header for the library. Just as they said, some_lib_struct_t was just a typedef for a pointer to actual_lib_struct_t. I made the following changes:

extern crate libc;

struct actual_lib_struct_t;
type some_lib_type_t = *mut actual_lib_struct_t;

#[link(name="some_lib")]
extern {
    fn some_lib_func(x: *mut some_lib_type_t);
}

fn main() {
    let mut x: some_lib_type_t;
    unsafe {
        x = std::mem::uninitialized();
        some_lib_func(&mut x);
    }
}

And it works! I do however get the warning found zero-size struct in foreign module, consider adding a member to this struct, #[warn(improper_ctypes)] on by default.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!