外部函数接口(FFI)
学习从 Rust 调用 C 库,并使用 FFI 将 Rust 函数提供给其他语言,以实现互操作。
外部函数接口(FFI) 是 CoddyKit 上的免费 Learn Rust Coding 课时。 这是第 1 节课,共 3 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Learn Rust Coding 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Learn Rust Coding 课程共包含 3 节课。
什么是 FFI?
FFI 代表外部函数接口(Foreign Function Interface)。它是一种机制,允许使用一种编程语言编写的程序调用另一种语言中定义的函数,或使用其中定义的数据结构。
在 Rust 中,FFI 让您可以与其他语言编写的代码进行交互,最常见的是 C。这对于集成现有库或系统 API 非常有用。
为什么要使用 FFI
FFI 不是日常开发中经常使用的工具,但在以下情况下非常强大:
- 利用现有的 C 库:许多高性能、成熟的库都是用 C/C++ 编写的。FFI 让 Rust 可以直接使用这些库。
- 系统 API:与可能仅提供 C 接口的操作系统功能进行交互。
- 互操作性:构建可供其他语言调用的 Rust 库,例如供 Python、Java 或通过 Node.js 使用的 JavaScript 调用。
从 Rust 调用 C:声明
要从 Rust 调用 C 函数,首先需要使用 extern "C" 代码块声明其签名。这会告诉 Rust C 函数的形式,但不会提供它的实现。
"C" 部分指定了 C 调用约定,从而确保函数调用彼此兼容。
extern "C" {
// Declare C functions here
// Example: int puts(const char *s);
fn puts(s: *const std::os::raw::c_char) -> std::os::raw::c_int;
// Example: int add(int a, int b);
fn add(a: std::os::raw::c_int, b: std::os::raw::c_int) -> std::os::raw::c_int;
}从 Rust 调用 C:`unsafe` 代码块
Rust 的核心承诺是内存安全。但是,当您通过 FFI 与 C 代码交互时,Rust 无法保证外部代码的安全性。
因此,对在 extern "C" 代码块中声明的 C 函数进行的任何调用,都必须放在 unsafe 代码块中。这是在向编译器和其他开发人员表明,您需要负责维护安全保证。
extern "C" {
// We're declaring that a C function `puts` exists.
fn puts(s: *const std::os::raw::c_char) -> std::os::raw::c_int;
}
fn main() {
let rust_string = "Hello from Rust via C!";
// C strings need to be null-terminated.
let c_string = std::ffi::CString::new(rust_string).expect("CString failed");
unsafe {
// Calling the C 'puts' function. This requires 'unsafe'.
puts(c_string.as_ptr());
}
println!("C function call demonstrated.");
}类型映射:从 Rust 到 C
使用 FFI 时,必须确保 Rust 类型能够正确映射到 C 类型。Rust 在 std::os::raw 和 std::ffi 中提供了专用类型来完成这项工作。
i32->std::os::raw::c_intf32->std::os::raw::c_floatbool->std::os::raw::c_uchar(或类似类型,因为 C 没有标准布尔类型)&str->*const std::os::raw::c_char(C 字符串需要以空字符结尾,通常由std::ffi::CString处理)&mut [T]->*mut T
请始终使用这些明确的 C 类型,以避免未定义行为。
示例:调用 C 的 `add` 函数
假设我们有一个 C 库,其中包含 int add(int a, int b); 函数。下面展示了如何从 Rust 调用它。请注意整数类型使用了 c_int。
(此代码演示了 FFI 语法,但如果没有外部链接的已编译 C 库,则无法运行。)
extern "C" {
// Declaration of the C function `add`
fn add(a: std::os::raw::c_int, b: std::os::raw::c_int) -> std::os::raw::c_int;
}
fn main() {
let x = 10;
let y = 20;
let result = unsafe {
// Call the C 'add' function within an unsafe block
add(x as std::os::raw::c_int, y as std::os::raw::c_int)
};
println!("Attempted to call C add. Result (if linked): {}", result);
}将 Rust 暴露给 C:基础知识
要让 C 调用 Rust 函数,需要完成两件事:
#[no_mangle]:此属性会阻止 Rust 编译器对函数名称进行“名称改编”(修改)。C 编译器需要简单且未经改编的名称。extern "C":此项指定函数使用 C 调用约定,使其能够与 C 兼容。
示例:供 C 调用的 Rust 函数
下面是一个用于计算总和、可以由 C 程序调用的 Rust 函数。请注意其中的 #[no_mangle] 和 extern "C" 属性。
(此代码设计为编译成供 C 使用的库,但在此环境中包含一个用于内部测试的 main。)
#[no_mangle]
pub extern "C" fn rust_add_and_print(
a: std::os::raw::c_int,
b: std::os::raw::c_int
) -> std::os::raw::c_int {
let sum = a + b;
println!("Rust function received: {} + {} = {}", a, b, sum);
sum
}
fn main() {
println!("This Rust code exposes a function for C.");
// We can also call it internally for demonstration
let result = rust_add_and_print(5, 7);
println!("Internal call result: {}", result);
}FFI 内存管理
跨越 FFI 边界进行内存管理至关重要。如果 Rust 分配了内存(例如字符串)并将指针传递给 C,那么 C 必须复制数据,或负责正确释放这块内存。
反过来,如果 C 分配了内存并将指针传递给 Rust,除非明确得到指示,否则 Rust 不应释放这块内存;或者,Rust 必须复制数据。
std::ffi::CString 和 CStr 等工具可以通过处理空字符结尾并确保所有权正确转移,帮助您安全地管理兼容 C 的字符串。
FFI 快速检查
让我们测试一下您对 Rust 外部函数接口的理解。
FFI:连接不同世界的桥梁
您已经学习了 Rust 的外部函数接口!
FFI 让 Rust 真正具备强大的互操作能力,您可以:
- 使用
extern "C"和unsafe代码块调用 C 库中的函数。 - 使用
#[no_mangle]和pub extern "C"将 Rust 函数暴露给其他语言。 - 使用
std::os::raw中的类型谨慎处理类型映射。
FFI 是将 Rust 集成到各种生态系统中的强大工具,但请务必谨慎使用,尤其要注意安全性和内存管理!
常见问题解答
「外部函数接口(FFI)」课时是免费的吗?
是的 — 「外部函数接口(FFI)」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Learn Rust Coding 课程的其余内容,请升级到 CoddyKit PRO。 Learn Rust Coding 课程共包含 3 节课。
「外部函数接口(FFI)」这节课中我会学到什么?
学习从 Rust 调用 C 库,并使用 FFI 将 Rust 函数提供给其他语言,以实现互操作。 你通过在浏览器中直接运行的动手代码来练习 Learn Rust Coding,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Learn Rust Coding 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Learn Rust Coding 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 3 节。
「外部函数接口(FFI)」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Learn Rust Coding 课中编写并运行代码吗?
能。每节 Learn Rust Coding 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 外部函数接口(FFI)
- Rust 与 WebAssembly(WASM)
- 基准测试与性能调优