When dealing with unix syscalls, you actually sometimes need to pass structs that aren't fully initialized, or are initialized to zero with the exception of some fields. The quintessential example is the sigaction struct.
#[repr("C")]
struct MyThing {
length: usize,
data: MaybeUninit<MyInner>
}
Then initialize with sizeof(data) and MaybeUninit::uninitialized(). When the call is complete, assume_init() and access the fields of the result struct as normal.