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.