← [ BACK_TO_NOTES ]

Rust FFI

通过 C ABI 与外部语言互操作;安全封装、所有权跨边界与工具链要点。

#concept #growing #dev #rust

[!info] related notes

Rust FFI

这个概念为什么出现

现实系统有 C 库、OS API、其他语言运行时。
FFI(Foreign Function Interface)让 Rust 调用/被调用,但类型与所有权契约需人工保证。

[!abstract] 一句话理解 extern "C" 声明 C ABI 函数;跨边界指针与生命周期须有明确契约,不能都靠运行时检查证明;可用 bindgen 生成声明,unsafe 留在薄封装内。

最小可运行示例

场景:在有 C 标准库的目标上调用 abs

use std::ffi::c_int;

unsafe extern "C" {
    fn abs(input: c_int) -> c_int;
}

fn checked_abs(value: c_int) -> Option<c_int> {
    if value == c_int::MIN {
        return None; // C abs 的结果无法表示时是未定义行为,不能调用。
    }
    // SAFETY: 签名匹配本平台 C abs;已排除结果无法表示的最小值。
    Some(unsafe { abs(value) })
}

fn main() {
    println!("abs={:?}", checked_abs(-12));
    assert_eq!(checked_abs(c_int::MIN), None);
}

使用 Rust 2024 的 unsafe extern 块;在带 C 标准库的 Linux 主机可用 rustc 编译,输出 abs=Some(12)。其他目标需核实 C 运行时和链接配置。实际 Rust 代码无需为绝对值引入 FFI,可用整数 checked_abs;这里专门演示 ABI 与输入契约。

结合场景再看三个关注点

  1. 跨边界无借用检查器
  2. 谁 free 内存必须写清
  3. 字符串用 CString/CStr

核心概念与准确模型

  • ABI:"C" 最常见
  • 表示:repr(C) 控制结构体布局,不使 String、Vec 或 Rust 引用自动成为可移植 C 接口;字段类型本身也要兼容
  • 工具:bindgen、cbindgen
  • 回调、线程、异常(C++)更复杂

设计动机

  • 复用生态
  • 渐进迁移
  • 性能关键路径

边界与误区

  • 把 String 指针直接丢给 C
  • 忽略对齐/打包
  • 不让 panic 或外部异常任意跨越 ABI;Rust panic 经过不允许 unwind 的 C ABI 边界会终止进程,C-unwind 是另一份需明确设计的契约

[!warning] 常见误区:大量 pub unsafe fn 直接暴露 能证明所有安全调用都有效时才给 safe 封装;无法建立该保证时保留 unsafe API 与 Safety 文档。bindgen 不会自动证明内存所有权、长度或回调生命周期。

工程实践

  1. 自动生成绑定
  2. 所有权表:谁分配谁释放
  3. 测试与 sanitizer 验证受支持场景;Miri 对实际外部 C 调用支持有限,不能代替目标平台集成验证
  4. 文档与示例强制

本节总结

  • FFI 是契约工程
  • unsafe 薄封装
  • 布局与字符串是高发坑

自测题

  1. 为什么需要 repr(C)?
  2. 谁应该 free C 分配的内存?
参考答案
  1. 保证与 C 兼容的字段布局。
  2. 按 API 契约,通常分配方或文档指定方。

延伸阅读与资料来源

资料类型支撑内容
The Book — FFI官方书extern
Rustonomicon — FFI官方FFI 细节
bindgen工具生成绑定
创建于 2026/7/15 更新于 2026/10/7
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本