tezvyn:

Rust's `extern` Block: Talking to Other Languages

AI-drafted, machine-checkedSource: doc.rust-lang.orgbeginner

An `extern` block is Rust's contract for calling code from other languages, like C. You declare external functions and statics, promising they exist. Use it for FFI to call system libraries, but know all calls are `unsafe` as Rust can't verify them.

WHY IT EXISTS Rust needs a way to interoperate with the vast ecosystem of existing code, most of which is written in C or exposes a C-compatible interface. extern blocks provide this bridge, allowing Rust programs to call functions and access data from non-Rust libraries, forming the basis of its Foreign Function Interface (FFI).

THE MENTAL MODEL Think of an extern block as a C header file (.h) translated into Rust syntax. You are not defining new functions, but merely declaring the signatures of functions that are defined elsewhere. You are making a promise to the compiler: "Trust me, a function with this name, these arguments, and this return type exists, and you can call it using this specific calling convention (ABI)."

HOW IT WORKS You declare an extern block using unsafe extern "ABI" { ... }, where the ABI (Application Binary Interface) string like "C" or "system" specifies the calling convention. Inside, you list function signatures without bodies (ending in a semicolon) and static variables without initializers. Calling these functions or accessing the statics requires an unsafe block because the Rust compiler cannot verify the safety of the external code. It trusts that your declarations are correct.

WHEN TO USE IT Use extern blocks whenever you need to perform FFI calls. This is common for three main reasons: first, interacting with operating system APIs (like the Windows API or POSIX functions); second, using a high-performance library written in C or C++; third, linking a Rust component into a larger, existing non-Rust application.

WHEN NOT TO USE IT Do not use extern blocks for code written purely in Rust. If you are calling functions from another Rust crate, use its public API via the use keyword. extern is specifically for bridging the gap with non-Rust code. Using it for Rust-to-Rust calls bypasses the safety guarantees and ABI stability that Cargo and the compiler provide.

ONE CANONICAL EXAMPLE A classic use case is calling the printf function from the standard C library. First, you declare its signature in an extern "C" block, specifying the C calling convention.

extern "C" { fn printf(format: *const std::ffi::c_char, ...) -> std::ffi::c_int; }

Then, you can call it from within an unsafe block in your Rust code, making sure to use a C-compatible string (null-terminated).

let message = "Hello from Rust!\n\0"; unsafe { printf(message.as_ptr() as *const i8); } This tells Rust exactly how to format the function call to be understood by the compiled C library.

Read the original → doc.rust-lang.org

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.