How to call a C function from Rust
Edit: Thanks to the This Week In Rust newsletter for including this guide in issue #463 🙌
Recently I was working on a Rust project where we needed to interact with code written in C.
I had to learn how to work with FFI (Foreign Function Interface) in Rust and wrote up this little guide based on my notes. Maybe it will help someone else.
Final result #
I initially made a repository on GitHub with the example code and then wrote up this tutorial to go along with it. To try it, clone the repository and run it using
This is the resulting output:
1. Define an external function #
extern to reference the
multiply() function, which is written in C (
In this case we want to multiply integers, so we import a C-compatible integer type into Rust from
core:ffi. (See all the available types)
We then define the argument types and return type for our C function as
c_int (equivalent to
i32 in Rust).
2. Call the C function from Rust #
Any use of foreign function is considered unsafe because the Rust compiler can’t guarantee memory safety in foreign code.
So in our main Rust file (
src/main.rs) we call the function in an
unsafe block, then pass in two
i32 integers, and print the result.
3. Compile and run #
First we compile our
multiply.c file using a C compiler:
-c flag tells the C compiler to output a “object file (
.o)” instead of an executable program. So it creates a
multiply.o file that we can use as a shared dynamic library in our Rust code.
Then we compile our program using the Rust compiler:
-l multiply.o option tells the Rust compiler to link the shared library.
-L . option tells the Rust compiler to look for libraries in the current directory.
The compiler creates an executable named
main which we can run:
4. Automate 🤖 #
It gets tedious to compile the files manually every time, so we will use cargo build script and the
cc crate to automate this process.
cc to the projects build dependencies:
build.rs and add compile instructions:
And now we can use Cargo to build both the C and Rust code and run the program:
See the final result above.
From Rust 1.64.0 it is now recommended to use
std::os::rawto access C types. The latter is now an alias to types in the
coreis also available in places where the Rust standard library (
std) is not, like embedded projects.
Mapping out functions manully using
externis fine for small projects, but as soon as you are dealing with a bigger library or codebase, you want to take a look at
bindgen. It can automatically generate the bindings for C or C++ libraries, making using them in Rust a lot easier. See the
We can control how our code is linked using the
#[link()]attribute.. It allows us to specify or rename functions and change the type of linking to use, eg. to static:
Further reading #
FFI chapter in The Rustonomicon book
(Rustonomicon is the official guide to unsafe Rust)
“A little C with your Rust” chapter in The Embedded Rust Book
(The official Embedded Rust guide)
📖 Chapter 11: “Foreign Function Interfaces” in Rust for Rustaceans
by Jon Gjengset
📖 Chapter 23: “Foreign Functions” in Programming Rust, 2nd Edition
by Jim Blandy, Jason Orendorff & Leonora F. S. Tindall
⏯ Crust of Rust: Build Scripts and Foreign-Function Interfaces (FFI)
(Contributed by @uggla)