Rust 与 C 的互操作:FFI 实战指南
在系统编程领域,Rust 很少能完全避开与 C 代码的交互。无论是调用系统库、集成遗留代码,还是为 C 项目提供 Rust 实现,FFI(Foreign Function Interface)都是必须掌握的技能。
基础 FFI 调用:
use std::os::raw::c_int;
extern "C" {
fn abs(input: c_int) -> c_int;
}
fn rust_abs(x: i32) -> i32 {
unsafe { abs(x) }
}
安全封装是 FFI 的核心原则:
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
// C 库接口
extern "C" {
fn process_string(input: *const c_char) -> *mut c_char;
fn free_string(s: *mut c_char);
}
// 安全的 Rust 封装
fn safe_process_string(input: &str) -> Result<String, std::ffi::NulError> {
let c_input = CString::new(input)?;
let result = unsafe {
let ptr = process_string(c_input.as_ptr());
if ptr.is_null() {
return Ok(String::new());
}
let c_str = CStr::from_ptr(ptr);
let output = c_str.to_string_lossy().into_owned();
free_string(ptr); // 释放 C 分配的内存
output
};
Ok(result)
}
回调函数的跨语言传递需要特别小心:
type Callback = extern "C" fn(i32) -> i32;
extern "C" {
fn register_callback(cb: Callback);
}
extern "C" fn my_callback(x: i32) -> i32 {
x * 2
}
fn main() {
unsafe { register_callback(my_callback); }
}
关键原则:在 unsafe 块的边界处建立安全不变量,让调用者无需关心底层的 C 代码。我们用这个模式封装了 50+ 个 C 库函数,上层 Rust 代码完全不包含 unsafe。