c - 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;
由于字节序会影响内存中的字节顺序,我几乎不明白为什么在小端架构中以这种方式定义结构
谢谢
解决方案
字节序也可以影响位,而不仅仅是字节,但是您通常看到效果的唯一时间是在位域中。这就是为什么结构中位域的顺序以及它们所在的字节偏移量是实现定义的原因之一。
查看这个定义,似乎暗示对于给定的实现,位域在大端系统上按物理顺序放置,而在小端系统上每个字节按相反的顺序放置。
具体来说,前 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
系列函数来正确读取占用超过一个字节的整数字段。
推荐阅读
- javascript - 在运行时解析模板字符串插值,而不是在包创建时
- reactjs - 调用一个 url,然后根据接收到的数据执行一些计算,然后调用另一个 url
- composer-php - 如何让作曲家本地包依赖项安装?
- html - 响应式按钮动画 CSS
- node.js - Firebase Storage Admin SDK:从图片网址上传
- visual-studio - 为什么我会收到包含 pch.h 的警告,即使它已经包含在内?
- python - Fashion-MNIST 数据集维度的困难
- kubernetes - kubernetes cronjob 只运行一次?
- bash - Git pull 在终端中有效,但在 bash 文件中无效(来自 webhooks)
- css - 如何声明多个字体并将它们中的每一个分配给一个变量并在样式组件中访问它们