Why does an 8-bit field have endianness?

2019-03-18 01:07发布

问题:

See the definition of TCP header in /netinet/tcp.h:

struct tcphdr
  {
    u_int16_t th_sport;         /* source port */
    u_int16_t th_dport;         /* destination port */
    tcp_seq th_seq;             /* sequence number */
    tcp_seq th_ack;             /* acknowledgement number */
#  if __BYTE_ORDER == __LITTLE_ENDIAN
    u_int8_t th_x2:4;           /* (unused) */
    u_int8_t th_off:4;          /* data offset */
#  endif
#  if __BYTE_ORDER == __BIG_ENDIAN
    u_int8_t th_off:4;          /* data offset */
    u_int8_t th_x2:4;           /* (unused) */
#  endif
    u_int8_t th_flags;
#  define TH_FIN        0x01
#  define TH_SYN        0x02
#  define TH_RST        0x04
#  define TH_PUSH       0x08
#  define TH_ACK        0x10
#  define TH_URG        0x20
    u_int16_t th_win;           /* window */
    u_int16_t th_sum;           /* checksum */
    u_int16_t th_urp;           /* urgent pointer */
};

Why does the 8-bit field have a different order in endianness? I thought only 16-bit and 32-bit fields mattered with byte order, and you could convert between endians with ntohs and ntohl, respectively. What would the function be for handling 8-bit things? If there is none, it seems that a TCP using this header on a little endian machine would not work with a TCP on a big endian machine.

回答1:

There are two kind of order. One is byte order, one is bitfield order. There is no standard order about the bitfield order in C language. It depends on the compiler. Typically, the order of bitfields are reversed between big and little endian.



回答2:

This is compiler-dependent and non-portable. How bit fields are ordered is implementation dependent, it would be far better here to use an 8-bit field and shift/mask to obtain the subfields.



回答3:

Its possible that in this machine the endianess also refers to the bit order as well as the byte order. This wikipedia article mentions that this is sometimes the case.



回答4:

My understanding is that bit ordering and endianness are generally two different things. Structures with bit-fields are generally not portable across compilers/architectures. Sometimes ifdefs can be used to support different bit orderings. In this case the endianness is really irrelevant and it should be an ifdef about the bit ordering. The assumption that some endianesses have a certain bit-order may be true in some cases.



回答5:

My reading of the comment is that the two one-byte fields together are construed as a two-byte value (or were -- seems like one byte is unused anyway). Rather than declare one two-byte value, they declare two one-byte values but reverse the order of declaration depending on endian-ness.



回答6:

It may help to know that this is code is only run if "# ifdef __FAVOR_BSD". It is from /usr/include/netinet/tcp.h

# ifdef __FAVOR_BSD
typedef u_int32_t tcp_seq;
/*
 * TCP header.
 * Per RFC 793, September, 1981.
 */
struct tcphdr