(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.