我需要弄清楚字节序如何影响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;
由于字节序会影响内存中的字节顺序,因此我几乎无法理解为什么在小字节序体系中以这种方式定义结构
谢谢
答案 0 :(得分:1)
字节序也会影响位,而不仅是字节,但是您通常只能在位域中看到效果。这就是为什么要定义结构中位域的顺序以及它们位于哪个字节偏移量的原因。
看这个定义,似乎意味着对于给定的实现,在大字节序系统上,位域在物理上是按顺序放置的,在小字节序系统上,对于每个字节,其位在相反的顺序上。
尤其是,前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
函数家族来正确读取占用一个以上字节的整数字段。
答案 1 :(得分:0)
除了字节顺序问题外,您还无法知道每个位域的位置。
每6.7.2 Type specifiers, paragraph 11 of the C Standard:
实现可以分配任何足够大的可寻址存储单元以容纳位字段。如果有足够的空间,则应将紧随结构中另一个位域之后的位域打包到同一单元的相邻位中。如果剩余空间不足,则实现的定义是将不适合的位字段放入下一个单元,还是将相邻单元重叠。单位内的位域分配顺序(从高位到低位或从低位到高位)由实现定义。未指定可寻址存储单元的对齐方式。
如果您需要确切地知道数据中的什么位置,则即使在同一平台上的不同编译器之间,也无法完全完全使用位域。