首页 > 解决方案 > C 中具有结构和字节序的位字段提取

问题描述

我需要澄清字节顺序如何影响 C 结构中的位提取字段。

以下结构声明了 rtp 标头:

typedef struct {
 #if BYTE_ORDER == BIG_ENDIAN
    unsigned int version:2; /* protocol version */
    unsigned int p:1;       /* padding flag */
    unsigned int x:1;       /* header extension flag */
    unsigned int cc:4;      /* CSRC count */
    unsigned int m:1;       /* marker bit */
    unsigned int pt:7;      /* payload type */
#else
   unsigned int cc:4;      /* CSRC count */
   unsigned int x:1;       /* header extension flag */
   unsigned int p:1;       /* padding flag */
   unsigned int version:2; /* protocol version */
   unsigned int pt:7;      /* payload type */
   unsigned int m:1;       /* marker bit */
#endif
  unsigned int seq:16;    /* sequence number */
  uint32_t ts;        /* timestamp */
  uint32_t ssrc;      /* synchronization source */
  uint32_t csrc[0];       /* optional CSRC list */
} rtp_hdr_t;

由于字节序会影响内存中的字节顺序,我几乎不明白为什么在小端架构中以这种方式定义结构

谢谢

标签: cendianness

解决方案


字节序也可以影响位,而不仅仅是字节,但是您通常看到效果的唯一时间是在位域中。这就是为什么结构中位域的顺序以及它们所在的字节偏移量是实现定义的原因之一。

查看这个定义,似乎暗示对于给定的实现,位域在大端系统上按物理顺序放置,而在小端系统上每个字节按相反的顺序放置。

具体来说,前 4 个位域占用 8 个位,接下来的 2 个位域占用 8 个位。所以在小端的情况下,前 4 个位域的顺序相互颠倒,最后 2 个位域相互颠倒。

这样的代码在系统头文件中很常见。例如,Linux 上的 /usr/include/netinet/in.h 包含以下用于对 IP 标头建模的结构:

struct iphdr
  {
#if __BYTE_ORDER == __LITTLE_ENDIAN
    unsigned int ihl:4;
    unsigned int version:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
    unsigned int version:4;
    unsigned int ihl:4;
#else
# error "Please fix <bits/endian.h>"
#endif
    u_int8_t tos;
    u_int16_t tot_len;
    u_int16_t id;
    u_int16_t frag_off;
    u_int8_t ttl;
    u_int8_t protocol;
    u_int16_t check;
    u_int32_t saddr;
    u_int32_t daddr;
    /*The options start here. */
  };

据推测,这个想法是一个包含原始网络数据包的缓冲区可以memcpy用来将字节复制到这个结构的一个实例中(或者只是让一个指向这个结构的指针指向缓冲区,如果它正确对齐的话)以简化序列化/反序列化。但是,您仍然需要调用htonx/ntohx系列函数来正确读取占用超过一个字节的整数字段。


推荐阅读