C - What does *(long *)(host->h_addr); do?

会有一股神秘感。 提交于 2019-12-24 00:48:25

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!