Rust 与 C 的互操作:FFI 实战指南

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。