On this page
Raw Pointers and FFI
*const Tand*mut Tare not constrained by the borrow checker—they can be aliased freely and may not point to valid memory. Their sole purpose is FFI: calling C libraries, receiving C callbacks, and manipulating hardware registers. An unsafe block does not "disable safety checks"; rather, it shifts safety responsibility from the compiler to the programmer.
Raw Pointers: Pointers Without a Borrow Checker
let x = 42;
let ptr: *const i32 = &x; // Reference → Raw Pointer (safe)
unsafe
Raw pointers do not need to adhere to borrow checker rules—you can have multiple *mut T pointing to the same data, they can be null, and alignment is not guaranteed. All responsibility shifts to the programmer.
Difference from C int *: Rust distinguishes between *const T and *mut T (similar to C's const int * vs int *). However, C can implicitly discard const, whereas Rust cannot.
extern "C": C Function Interface
extern "C"
// Prevent Rust name mangling
pub extern "C"
extern "C" uses the C calling convention: arguments are arranged in registers/stack according to the target platform's C ABI. On x86-64, this is the System V AMD64 ABI (arguments passed via rdi, rsi, rdx, rcx, r8, r9). You can also use extern "system" (Windows API) and extern "Rust" (default).
#[repr(C)]: C-Compatible Memory Layout
// size: 16 bytes
Without #[repr(C)], the Rust compiler may reorder fields to optimize struct size. With #[repr(C)], fields are ordered as declared, with padding added according to C ABI requirements—ensuring binary compatibility with C structs. #[repr(C, packed)] eliminates all padding (but may create unaligned references—unsafe).
bindgen: Automatically Generate Rust FFI Bindings
Generate Rust extern declarations, struct definitions, and constants from C headers:
// build.rs:
// src/lib.rs:
include!;
Callbacks: The Trap of C Calling Rust
extern "C"
unsafe
When passing Rust functions as callbacks to C, panics cannot cross FFI boundaries—if a panic occurs within the callback and unwinding crosses the C stack frame, this is UB (C stacks do not have unwind tables). Solutions: catch panics within the callback using std::panic::catch_unwind, or set panic = "abort" in Cargo.toml.
References
- Rustonomicon: FFI, C ABI
- bindgen: rust-lang.github.io/rust-bindgen
- The Embedded Rust Book: FFI and C interaction
*Keywords: raw pointer, *const, mut, extern "C", #[no_mangle], repr(C), bindgen, FFI callback, C ABI