使用Rust FFI时如何初始化不透明的C结构?

问题描述 投票:9回答:2

这是我想用C代码做的事情:

#include <some_lib.h>
int main() {
    some_lib_struct_t x;
    some_lib_func(&x);
}

如何在Rust中使用库?这是我到目前为止所得到的:

extern crate libc; // 0.2.51

struct some_lib_struct_t;

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

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

编译时我收到一个错误:

error[E0381]: borrow of possibly uninitialized variable: `x`
  --> src/main.rs:13:23
   |
13 |         some_lib_func(&mut x);
   |                       ^^^^^^ use of possibly uninitialized `x`
rust ffi
2个回答
8
投票

最安全的答案是自己初始化结构:

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

与C代码最接近的模拟是使用mem::uninitialized

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

你必须确保some_lib_func完全初始化结构的所有成员,否则不安全将泄漏到unsafe块之外。

说到“结构的成员”,我几乎可以保证你的代码不会做你想要的。你已经将some_lib_struct_t定义为零大小。这意味着不会为它分配任何堆栈空间,并且对它的引用将不是您的C代码所期望的。

您需要在Rust中镜像C结构的定义,以便可以分配适当的大小,填充和对齐。通常,这意味着使用repr(C)

很多时候,C库总是通过返回指向opaque类型的指针来避免暴露它们的内部结构表示:


0
投票

读完Shepmaster's answer之后,我仔细看了一下图书​​馆的标题。就像他们说的那样,some_lib_struct_t只是指向actual_lib_struct_t的指针。我做了以下更改:

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);
    }
}

它的工作原理!然而我确实得到警告found zero-size struct in foreign module, consider adding a member to this struct, #[warn(improper_ctypes)] on by default

© www.soinside.com 2019 - 2024. All rights reserved.