Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

An extern function in Rust is a language-level construct that facilitates a Foreign Function Interface (FFI), enabling Rust to interoperate with code compiled in other languages. The extern keyword explicitly defines the Application Binary Interface (ABI) for a given function, ensuring that calling conventions, argument passing, and memory layouts align between the Rust compiler and the foreign language compiler. The extern keyword is utilized in two distinct contexts: importing foreign functions into Rust, and exporting Rust functions to be consumed by foreign environments.

Importing Foreign Functions

To declare functions defined in another language, Rust uses an extern block. The block specifies the ABI string (most commonly "C") and contains function signatures without bodies. Because the Rust compiler cannot analyze foreign code to enforce its strict borrowing and memory safety guarantees, all functions declared within an extern block are implicitly considered unsafe. Invoking them requires an explicit unsafe block.
use std::ffi::c_int;

// Declares an external block using the standard C ABI
extern "C" {
    // Function signature matching the foreign C function
    fn abs(input: c_int) -> c_int;
}

fn main() {
    let x = -42;
    
    // Invocation requires an unsafe block
    let result = unsafe {
        abs(x)
    };
    
    println!("Result: {}", result);
}

Exporting Rust Functions

To expose a Rust function to a foreign language, the extern keyword is applied directly to the function definition, alongside the target ABI. Additionally, the #[no_mangle] attribute must be applied. By default, the Rust compiler alters function names during compilation (name mangling) to encode module and type information. #[no_mangle] disables this behavior, ensuring the function’s symbol is exported exactly as written so the foreign linker can resolve it.
use std::ffi::c_int;

// Disables name mangling and specifies the C ABI
#[no_mangle]
pub extern "C" fn add_numbers(a: c_int, b: c_int) -> c_int {
    a + b
}

Application Binary Interfaces (ABIs)

The string literal following the extern keyword dictates the ABI. If the string is omitted (e.g., extern { ... }), Rust defaults to "C". Supported ABI strings include:
  • "C": The standard C ABI (most common).
  • "system": The default ABI for interacting with the target operating system’s APIs (e.g., maps to "stdcall" on 32-bit Windows and "C" on most other platforms).
  • "stdcall", "win64", "sysv64": Platform-specific calling conventions.
  • "Rust": The default Rust ABI (implicit for standard Rust functions, rarely written explicitly).

FFI-Safe Types

When defining extern functions, the parameters and return types must cross the FFI boundary safely. Rust provides the std::ffi and std::os::raw modules, which contain type aliases (like c_int, c_char, c_void) that map directly to their C equivalents on the target architecture. If passing custom data structures across the extern boundary, the Rust struct must be annotated with #[repr(C)] to force the compiler to lay out the struct’s memory exactly as a C compiler would, preventing Rust’s default field-reordering optimizations.
use std::ffi::c_int;

#[repr(C)]
pub struct Point {
    pub x: c_int,
    pub y: c_int,
}

extern "C" {
    fn process_point(p: *const Point);
}
Master Rust with Deep Grasping Methodology!Learn More