Rust: Expose Functions to C with `#[no_mangle]`
The `#[no_mangle]` attribute tells the Rust compiler not to alter a function's name, exposing a stable symbol for C code to call. Use it with `extern "C"` to create Rust libraries for other languages. The footgun is forgetting `extern "C"`, causing crashes.
WHY IT EXISTS: By default, the Rust compiler "mangles" function names to encode information like module paths, ensuring uniqueness within a Rust project. A function named process might become _ZN4my_crate7process17hdeadbeef.... This mangled name is unusable by external C code, which expects a simple, stable name like process. We need a way to tell Rust to produce a C-compatible function symbol.
THE MENTAL MODEL: Think of #[no_mangle] as putting a permanent, public name tag on a Rust function. Without it, Rust gives the function a complex, internal-only ID. With it, anyone outside (like a C linker) can find the function by its simple, declared name. It's the difference between a private employee ID and a public "Hello, My Name Is..." sticker.
HOW IT WORKS: The #[no_mangle] attribute instructs the compiler to inhibit name mangling for the item it's attached to. This exports the function with the exact name from your source code. For it to be callable from C, you must also use extern "C". This second piece tells the compiler to use the C Application Binary Interface (ABI), which defines how arguments are passed and who cleans up the stack. Using both ensures the name is findable and the call mechanics are compatible.
WHEN TO USE IT: Use #[no_mangle] and extern "C" when writing a Rust library that needs to be called from a non-Rust language. This is the foundation for creating dynamic libraries (.so, .dll, .dylib) or static libraries (.a) in Rust for consumption by C, C++, Python (via ctypes), Ruby, Node.js, and others.
WHEN NOT TO USE IT: Do not use it for functions that are only called from other Rust code. Rust's default name mangling and ABI are more optimized and support features like generics and trait methods, which a C ABI does not. Using it on internal-only functions discards potential compiler optimizations and safety features.
ONE CANONICAL EXAMPLE: To create a Rust function add that can be called from C, you would write: #[no_mangle] pub extern "C" fn add(left: i32, right: i32) -> i32 { left + right } A C program could then declare int32_t add(int32_t, int32_t); and call it after linking against the compiled Rust library. Note the use of pub, extern "C", and C-compatible types like i32.
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.