Here's what I would like to do in C code:
#include <some_lib.h>
int main() {
some_lib_struct_t x;
some_lib_func(&x);
}
How do I make use of the library in Rust? Here's what I've got so far:
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);
}
}
When compiling I get an error:
error[E0381]: borrow of possibly uninitialized variable: `x`
--> src/main.rs:13:23
|
13 | some_lib_func(&mut x);
| ^^^^^^ use of possibly uninitialized `x`
The safest answer is to initialize the struct yourself:
The closest analog to the C code is to use
MaybeUninit
Before Rust 1.36, you can use
mem::uninitialized
:You have to be sure that
some_lib_func
completely initializes all the members of the struct, otherwise the unsafety will leak outside of theunsafe
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:
From the documentation for
mem::uninitialized()
:The new solution would look like this:
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 toactual_lib_struct_t
. I made the following changes: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
.