FFI β Calling C Libraries from Rust
Practical use of extern "C", bindgen, and unsafe
No matter how large the Rust ecosystem grows, it can't replace all existing C/C++ libraries. SQLite, OpenSSL, libcurl β these need direct calling from Rust.
extern "C" {
fn strlen(s: *const c_char) -> usize;
}
let len = unsafe { strlen(c_str.as_ptr()) };
unsafe is needed because C functions don't follow Rust's ownership/borrowing rules. Pass a null pointer and you get a segfault.
bindgen auto-generates Rust bindings from C header files (.h).
Reverse direction (calling Rust from C): #[no_mangle] pub extern "C" fn β exactly how VOICEVOX Core exposes its C ABI to Python Engine.
Key Points
Declare C function signatures in extern "C" block
Link C library in build.rs (println!("cargo:rustc-link-lib=..."))
Call C functions in unsafe blocks β programmer guarantees safety
Wrap in safe Rust wrapper functions to provide safe API to users
Pros
- ✓ Access to entire C/C++ ecosystem's libraries from Rust
- ✓ Wrapping unsafe in wrappers keeps the rest safe
Cons
- ✗ Safety of unsafe code is programmer responsibility
- ✗ C library build configuration is complex per platform