【问题标题】:how does endianness affect bitfield defintion in struct?字节序如何影响结构中的位字段定义?
【发布时间】:2019-12-04 00:49:52
【问题描述】:

使用 iphdr 作为第一个示例:

struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
    __u8    ihl:4,
            version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
    __u8    version:4,
            ihl:4;
#else
#error  "Please fix <asm/byteorder.h>"
#endif

    /* other fields are emitted. */
};

我的问题 1,据我所知,字节序仅在处理多字节时才会影响,换句话说,如果只有 1 个字节,就没有“位顺序”这样的事情。在上面的定义中,ihl+version= 8 bits = 1 byte,ihl和version在一个字节中,为什么要关心ihl和version的字节序和倒序呢?

如果“位顺序”是个问题,我的问题 2 是为什么另一个 struct ip_options 不关心字节顺序?

struct ip_options {
    __be32      faddr;
    __be32      nexthop;
    unsigned char   optlen;
    unsigned char   srr;
    unsigned char   rr;
    unsigned char   ts;
    unsigned char   is_strictroute:1,  // why this byte doesn't care endianness?
                    srr_is_hit:1,
                    is_changed:1,
                    rr_needaddr:1,
                    ts_needtime:1,
                    ts_needaddr:1;
    unsigned char   router_alert;
    unsigned char   cipso;
    unsigned char   __pad2;
    unsigned char   __data[0];
};

【问题讨论】:

  • 这是 linux 源代码吗?我相信struct ip_options 不会脱离内核,所以没有人关心位域的顺序是否改变。至于struct iphdr,我猜ip头是这个结构的别名,所以你必须管理你的编译器来生成正确的代码。
  • 字节序定义了位的顺序,从最低到最高或从最高到最低。这也会影响位域。
  • byte(或更大)中位字段的顺序取决于编译器的实现。出于这个原因,最好尽可能避免使用位字段(例如使用 shifting 代替

标签: c endianness


【解决方案1】:

C 不需要字节字节序来指示 __u8 ihl:4 使用 4 MSBits 还是 4 LSBits。

我们为什么要关心 ihl 和版本的字节顺序和倒序?

原作者可能希望在硬件地址上覆盖struct iphdr,玩弄union 魔术或实现某种串行通信顺序。

该方法的可移植性不高,但可能已经满足了最初的有限需求。

如果“位顺序”是个问题,我的问题 2 是为什么另一个 struct ip_options 不关心字节顺序?

这是一个反复无常。

处理标题后的字节序可能无关紧要。标头类型struct iphdr 可能需要与字节序无关的编码,但是一旦分配了这些成员,剩余的代码就会相应地进行解释。如果除标头之外的所有内容都具有#if defined(__LITTLE_ENDIAN_BITFIELD),则可能是这种情况。

.tiff 做了这样的事情。

【讨论】:

    【解决方案2】:

    C 标准几乎完全未指定位域实现,因此无法判断。

    6.7.2.1 Structure and union specifiers, paragraph 11:

    实现可以分配任何大到足以容纳位字段的可寻址存储单元。如果有足够的空间,结构中紧跟在另一个位域之后的位域将被打包到同一单元的相邻位中。如果剩余空间不足,则将不适合的位域放入下一个单元还是与相邻单元重叠是实现定义的。 单元内位域的分配顺序(从高位到低位或从低位到高位)由实现定义。未指定可寻址存储单元的对齐方式。

    实际上没有可移植的方式来使用 C 中的位域。唯一指定的是“如果剩余空间足够”部分。但即使该空间的大小可能完全悬而未决,因为“[a]n 实现可以分配任何大到足以容纳位字段的可寻址存储单元。”

    【讨论】:

    • “在 C 中实际上没有可移植的方式来使用位域” --> 更像是没有完全可移植的,因为在实践中,某种程度的可移植性是可能的——甚至如果坑洼仍然存在。然而,您的主要观点是如此真实:“几乎完全未指明”。
    猜你喜欢
    • 1970-01-01
    • 2018-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-12
    • 1970-01-01
    • 2018-02-10
    • 2013-05-31
    相关资源
    最近更新 更多