2

Why order of ip_hl and ip_v changes by system byteorder?

I have to care about byteorder when the binary string is lager than 1 byte. However, the ip_hl and ip_v are in a byte, so I think I need not to care about byteorder of ip_hl and ip_v.

struct ip {
#if BYTE_ORDER == LITTLE_ENDIAN 
    u_char  ip_hl:4,        /* header length */
        ip_v:4;         /* version */
#endif
#if BYTE_ORDER == BIG_ENDIAN 
    u_char  ip_v:4,         /* version */
        ip_hl:4;        /* header length */
#endif
    u_char  ip_tos;         /* type of service */
    short   ip_len;         /* total length */
    u_short ip_id;          /* identification */
    short   ip_off;         /* fragment offset field */
...
};

`

q2ven
  • 187
  • 9

1 Answers1

1

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.

dbush
  • 205,898
  • 23
  • 218
  • 273