The ip_v
and ip_hl
fields are bit-fields. The order of bit-fields in a struct is not guaranteed by the standard.
From section 6.7.2.1 of the C standard:
11 An implementation may allocate any addressable storage unit large enough to hold a bitfield. If enough space remains, a bit-field that
immediately follows another bit-field in a structure shall be packed
into adjacent bits of the same unit. If insufficient space remains,
whether a bit-field that does not fit is put into the next unit or
overlaps adjacent units is implementation-defined. The order of
allocation of bit-fields within a unit (high-order to low-order or
low-order to high-order) is implementation-defined. The alignment of
the addressable storage unit is unspecified.
In the case of this particular struct, which represents an IP header, it is one defined in the system header files, so it has some implementation knowledge regarding the order of bitfields. Because an IP header must have the version field first followed by the header length, the #if
checks the endianness of the system to determine which order to place the fields in the struct so that they end up in the proper place, allowing the struct to be overlaid onto a received packet buffer to read the IP header. Presumably, a little endian system will reverse the order of bitfields while a big endian system will not.
This is not however something that you should attempt to do in user code, as it could behave differently on different systems. Code like this is permissible in system headers because they reside in a specific implementation where certain assumptions can safely be made.