Summary - FFI
- Rust course
- Advanced
- Lesson 41/81
- 5 min
Combine extern, repr(C) and CString to wrap a C call sending a string.
FFI summary
C functions are declared in an unsafe extern "C" block with C types (c_int, c_char, c_void). Shared structs must be #[repr(C)]. Strings are bridged with CString (Rust → C) and CStr (C → Rust). Callbacks are extern "C" fn, and panics can't cross the boundary. Resources are freed in Drop with the allocating side's function. For the reverse direction, #[unsafe(no_mangle)] pub extern "C" fn is used.
Offering a function to C
A library written in Rust can be called from C or other languages (Python, Swift). In Cargo.toml, crate-type = ["cdylib"] produces a shared library:
#[unsafe(no_mangle)]
pub extern "C" fn rs_topla(a: i32, b: i32) -> i32 {
a + b
}
// C side:
// int32_t rs_topla(int32_t a, int32_t b);This function can also be called from Rust like a normal function, and assigned to a pointer of type extern "C" fn(i32, i32) -> i32. cbindgen generates the C header automatically.
Practice Exported function
Write the rs_topla function above. Assign it to a function pointer with let f: extern "C" fn(i32, i32) -> i32 = rs_topla; and print the result of f(3, 4).
Starter code
fn main() {
// buraya yaz
}Sample solution
#[unsafe(no_mangle)]
pub extern "C" fn rs_topla(a: i32, b: i32) -> i32 {
a + b
}
fn main() {
let f: extern "C" fn(i32, i32) -> i32 = rs_topla;
println!("{}", f(3, 4));
}Expected output
7
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 What is <code>#[no_mangle]</code> for?
- It stops the compiler from changing the symbol name, so C finds the function by name Correct answer
- It hides the function
- It inlines it
- It turns off debugging
Explanation: Rust encodes symbol names with the module path (mangling); for exported functions this is turned off. In Rust 2024 it's written #[unsafe(no_mangle)].
2 Exported function
#[unsafe(no_mangle)]
pub ____ fn rs_topla(a: i32, b: i32) -> i32 {
a + b
}
#[unsafe(no_mangle)]
pub extern "C" fn rs_topla(a: i32, b: i32) -> i32 {
a + b
}
Explanation: A function called from C is defined with the C calling convention.
3 Group summary
| Term | Meaning |
|---|---|
extern "C" { } |
Call C |
#[repr(C)] |
C layout |
CString/CStr |
String bridge |
#[unsafe(no_mangle)] |
Offer to C |