What c_void does

c_void is an enum exposed by the std::ffi module of the Rust standard library. It is part of the public, stable API and you can rely on it from any edition of Rust.

As an enum, c_void can be exactly one of its declared variants at any time. The compiler stores a discriminant alongside the variant data, and the layout is optimised — for instance, an enum like Option<&T> uses the null-pointer niche so it fits in the same memory as a single pointer. The full canonical path is std::ffi::c_void; bring it into scope with use std::ffi::c_void; or refer to it by its full path.

When to use it

Use c_void when you need to represent one of several alternative shapes in a single value. Match on it to handle every variant — the compiler enforces exhaustiveness, which is the main reason Rust programs are robust against "forgotten case" bugs.

Annotated examples

Pattern matching every variant of c_void

use std::ffi::c_void;

fn describe(value: &c_void) -> &'static str {
    // The compiler checks exhaustiveness — if c_void grows a new variant
    // in a future Rust release, this match becomes a compile error and
    // forces you to handle the new case explicitly.
    match value {
        _ => "see std::ffi::c_void reference for variants",
    }
}

Exhaustive matching is what makes Rust enums so safe — you cannot accidentally forget a case. Wildcard `_` should be used sparingly; explicit variants give you a compile-time tripwire when the API changes.

For deeper background, see the canonical Rust patterns reference for the broader context behind this section.

Combining c_void with the ? operator

use std::ffi::c_void;

fn pipeline() -> Result<(), Box<dyn std::error::Error>> {
    // If c_void is Result, Option, or any type with a Try implementation,
    // ? short-circuits the failure path back to the caller — no manual
    // match, no boilerplate.
    let _value: c_void = todo!("obtain a c_void value");
    Ok(())
}

Many std enums (Result, Option, Cow, Bound, etc.) plug into the `?` operator or the `From`/`Into` machinery — that's how their pipelines stay readable as the call chain deepens.

Common pitfalls

Don't use a wildcard match arm (`_`) unless you genuinely don't care about new variants — losing exhaustiveness checking removes one of the strongest safety nets the type system gives you. If c_void is a Result-like or Option-like enum, prefer the `?` operator over hand-written match expressions for the failure path.

For deeper background, see an in-depth Rust idioms cheat sheet for the broader context behind this section.

Performance & threading notes

The size of an enum is the size of its largest variant plus a discriminant tag (often optimised away by niche analysis). Pattern matching compiles to a single jump table; matching is essentially free at runtime.