How to Call Unsafe Functions in Rust

You call unsafe functions in Rust by wrapping the function call inside an `unsafe` block, which explicitly tells the compiler you have manually verified that the operation is safe to perform.

You call unsafe functions in Rust by wrapping the function call inside an unsafe block, which explicitly tells the compiler you have manually verified that the operation is safe to perform. This mechanism is required because unsafe functions can violate Rust's safety guarantees, such as dereferencing raw pointers or calling external C code, and the compiler cannot automatically verify their correctness.

Here is a practical example of calling an unsafe function that dereferences a raw pointer:

fn main() {
    let x = 42;
    let ptr = &x as *const i32;

    // The call must be inside an unsafe block
    let value = unsafe {
        *ptr
    };

    println!("Value: {}", value);
}

If you are calling an unsafe function defined in your own code, you must also mark the function definition with the unsafe keyword. The caller is responsible for ensuring the preconditions are met before entering the block.

// Definition of an unsafe function
unsafe fn divide(a: i32, b: i32) -> i32 {
    // This could panic or cause undefined behavior if b is 0
    a / b
}

fn main() {
    let result = unsafe {
        divide(10, 2)
    };
    println!("{}", result);
}

When calling external C functions via FFI, the pattern remains the same. You declare the external function as extern "C" and mark it unsafe, then call it within an unsafe block.

use std::os::raw::c_int;

extern "C" {
    fn printf(format: *const i8, ...);
}

fn main() {
    let msg = b"Hello from Rust!\0";
    unsafe {
        printf(msg.as_ptr() as *const i8);
    }
}

Remember that the unsafe block only suppresses the compiler's safety checks for the code inside it; it does not make the code itself safe. You must manually ensure that raw pointers are valid, data races are avoided, and invariants are maintained. If you violate these rules, you risk undefined behavior, which can crash your program or corrupt memory. Use unsafe sparingly and only when absolutely necessary, documenting exactly why it is safe in the function's documentation comments.