问题
I found the following code in this example:
addr.sin_addr.s_addr = *(long *)(host->h_addr);
h_addr
is is a char
pointer and host
is a pointer to a struct of type hostent
. addr
is a struct of type sockaddr_in
and sin_addr
is a struct of type in_addr
. s_addr
is a uint32
.
Most of this information can be found here: http://man7.org/linux/man-pages/man7/ip.7.html
I'm pretty sure (long)
casts the char to a long, but I don't know what the extra asterisks do, especially because s_addr
is not a pointer.
Can someone explain what is happening here?
回答1:
(long *)(host->h_addr)
means to interpret host->h_addr
as a pointer to a long
. This is not very portable, but presumably a long
is 32 bits long on the system this was written for.
The additional star in *(...)
dereferences what is now a long
for assignment. This effectively copies all four bytes of the original char
array into the single long
value addr.sin_addr.s_addr
. Compare to (long)(*host->h_addr)
, which would only copy the first char
element.
This technique is extremely unportable. It assumes both the size and endianness of the long
type. You might be tempted to take a hint from the fact that s_addr
is a uint32
and do:
addr.sin_addr.s_addr = *(uint32_t *)(host->h_addr);
This is not really any better because the endianness is still undermined. Also,uint32_t
is guaranteed to hold at least 32 bits. It can be any larger number of bits, which would invoke undefined behavior when you tried to read unallocated memory with the copy (imagine copying your 32 bits of char
data as a 64-bit integer).
There are two options going forward:
If your char
array is already in the correct byte order (i.e., you don't care if h_addr[0]
represents the highest or lowest byte of a local uint32_t
), use memcpy
:
memcpy(&(addr.sin_addr.s_addr), host->h_addr, 4);
This is likely to be the approach you need. If, on the other hand you want h_addr[0]
to always end up in the highest byte, you need to respect the endianness of your system:
addr.sin_addr.s_addr = (host->h_addr[0] << 24) + (host->h_addr[1] << 16) + (host->h_addr[2] << 8) + (host->h_addr[3]);
There probably need to be some casts to uint32_t
along the way there.
回答2:
The way I'd read this is "addr.sin_addr.s_addr equals object of cast to long
pointer of host->h_addr", or more briefly, "addr.sin_addr.s_addr equals the long
pointed to by host->h_addr". host->h_addr
is presumably a pointer to something other than long
- here this address is treated as a pointer-to-long and the long it's pointed to is assigned to addr.sin_addr.s_addr
.
HTH.
来源:https://stackoverflow.com/questions/52266584/c-what-does-long-host-h-addr-do