Since the address of the first member-variable in a struct is guaranteed to be the same as the address of the struct itself, and since the chances of that particular struct ever being modified are close to zero (since doing so would break backwards-compatibility with just about every already-compiled networking executable in the world), in this case it doesn't really matter.
In principle, however, you can imagine a scenario where someone inserts another member-variable at the top of struct in_addr
, at which point your first example (with the casting) would break, while the second one would continue to work (after a recompile, of course).
As a general rule, avoiding explicit casts whenever possible is a good idea, because the casting tends to override the compiler's reporting of errors due to programming mistakes, leading to what could have been a compiler-error turning into a run-time failure that impacts users and/or takes a good amount of detective work to diagnose and fix.
As for why the in_addr
struct is needed -- when they were designing the BSD sockets API, they were designing it to be able to support an arbitrary number of multiple networking protocols equally well, despite the fact that each networking protocol has its own addressing-scheme with different data to keep track of. The easiest way to do that (from a software-design perspective) is to give each protocol its own set of defined structs, and design the API calls to take a pointer-to-whatever-type-of-struct, along with a struct-size value, so that the same function calls can be used in conjunction with any supported protocol. So in_addr
is the struct defined for the IPv4 protocol's idea of a network-address; the fact that it has only one member-variable in it is just a consequence of the (relative) simplicity of the IPv4 protocol's addressing scheme, but that fact wasn't considered worth breaking the struct-per-protocol abstraction over.