When looking at unix-socket
, I came across this code:
let timeout = unsafe {
let mut timeout: libc::timeval = mem::zeroed();
let mut size = mem::size_of::<libc::timeval>() as libc::socklen_t;
try!(cvt(libc::getsockopt(self.0,
libc::SOL_SOCKET,
kind,
&mut timeout as *mut _ as *mut _,
&mut size as *mut _ as *mut _)));
timeout
};
I was curious about these lines in particular:
&mut timeout as *mut _ as *mut _,
&mut size as *mut _ as *mut _
Why is it necessary to perform two casts to a mutable raw pointer in a row? Why wouldn't it have been sufficient to only cast once?
The timeout
for example corresponds to a *mut c_void
parameter:
pub unsafe extern fn getsockopt(sockfd: c_int, level: c_int, optname: c_int,
optval: *mut c_void, optlen: *mut socklen_t) -> c_int
The timeout
in that file is defined as:
let mut timeout: libc::timeval = mem::zeroed();
So it's of type libc::timeval
. Now let's consider:
&mut timeout as *mut _ as *mut _
First you have &mut timeout
so that is of type &mut libc::timeval
. Then you do as *mut _
to coerce it to a raw mutable pointer of an inferred type, which in this case is the same type of libc::timeval
, so the full type so far is: *mut libc::timeval
, which doesn't match the parameter type *mut c_void
. The final as *mut _
again infers the target type, which is now the parameter type *mut c_void
, so this finally coerces the *mut libc::timeval
to a *mut c_void
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With