为什么字节内的位端序很重要?

6
以下是Linux机器上从库中获取的IP结构。
   struct ip
      {
    #if __BYTE_ORDER == __LITTLE_ENDIAN
        unsigned int ip_hl:4;               /* header length */
        unsigned int ip_v:4;                /* version */
    #endif
    #if __BYTE_ORDER == __BIG_ENDIAN
        unsigned int ip_v:4;                /* version */
        unsigned int ip_hl:4;               /* header length */
    #endif
        u_int8_t ip_tos;                    /* type of service */
        u_short ip_len;                     /* total length */
        u_short ip_id;                      /* identification */
        u_short ip_off;                     /* fragment offset field */
    #define IP_RF 0x8000                    /* reserved fragment flag */
    #define IP_DF 0x4000                    /* dont fragment flag */
    #define IP_MF 0x2000                    /* more fragments flag */
    #define IP_OFFMASK 0x1fff               /* mask for fragmenting bits */
        u_int8_t ip_ttl;                    /* time to live */
        u_int8_t ip_p;                      /* protocol */
        u_short ip_sum;                     /* checksum */
        struct in_addr ip_src, ip_dst;      /* source and dest address */
      };

对于这些代码:

    #if __BYTE_ORDER == __LITTLE_ENDIAN
        unsigned int ip_hl:4;               /* header length */
        unsigned int ip_v:4;                /* version */
    #endif
    #if __BYTE_ORDER == __BIG_ENDIAN
        unsigned int ip_v:4;                /* version */
        unsigned int ip_hl:4;               /* header length */
    #endif

为什么字节内部的字节序很重要? 我认为字节序只影响多字节整数,但在这里似乎字节序也会影响字节内部的位排列?
此外,它只是一个字节,为什么是无符号整数,而无符号整数占用4个字节。
我注意到在wireshark中,ip_v和ip_hl显示为0x45。如果我捕获IP数据包。第一个字节由ip_v和ip_hl组成,我将其放入字符变量x中。
那么,x & 0b11110000的结果是什么?无论字节序如何,它始终是4还是可能是5?

可能是为什么8位字段具有字节序?的重复问题。 - Sergey Kalinichenko
x & 0b11110000 的结果是什么?无论大小端是否一致,它总是4吗?还是可能是5? - misteryes
是的,0x45&0b1110000 的结果始终是0x40,无论字节顺序如何。但是,位字段("冒号四" :4 东西)可以由编译器以任何顺序放置。因此,如果您分配ip_hl=4,ip_v=5,则可能会获得0x450x54,具体取决于编译器(编译器通常在决定半字节的字节级大小端时遵循字节的大小端)。 - Sergey Kalinichenko
2个回答

3
在涉及多字节数据时,存在与字节顺序有关的排序方式。但在您的情况下,重要的是位域排序,它处理单个字节数据中位的顺序。C标准没有规定位域排序的规则。它取决于实现并由编译器决定。
变量的大小不是4个字节,只有4个位。它们不是独立的变量,而是结构体内的位域。

它只有一个字节,为什么它的类型是无符号整数,而无符号整数却有4个字节。 - misteryes
1
"unsigned int"后跟冒号和一个整数,例如"unsigned int ip_v:4",是位域的声明。如果有帮助的话,可以将其视为“大小为4位的无符号整数”(严格来说,在声明位域时不能使用其他类型)。 - Luis

2

字节序定义了最高有效位(MSB)的位置,它与变量中的数字在内存中的解释方式有关。对于无符号整数:

00000001 (Binary) = 1 (2 to the power of 0) -> If the most significant bit is to the left

00000001 (Binary) = 128 (2 to the power of 7) -> If the most significant bit is to the right

从内存中数字的表示来看,即使在8位数字中,最高有效位的位置也非常重要。

对于你的最后一个问题,你是正确的,无论它是1字节还是4字节,因为它只占用4个位。但请记住,无符号整数并不总是4字节。

希望这有所帮助!


那么 x & 0b11110000 的结果是什么呢?无论大小端,它总是4吗?还是可能是5?我对此非常困惑。 - misteryes
2
这是误导性的。就 C 语言而言,二进制 00000001 (0x01) 在十进制中 总是 等于 1。例如,右移 运算符 >> 将(正)数字大致减半,而不是加倍:4>>1 == 2。正如其他人指出的那样,优先顺序取决于 位域。 标准的 §6.7.2.1,第 11 段规定了“对于单元内位域的分配顺序(高到低或低到高)是由实现定义的。” - jerry
但问题并不是关于C语言中的字节序,当然,在几乎所有计算机语言中,同一条指令在不同硬件上都应该以相同的方式工作。如果您注意代码,它似乎正在处理来自硬件接口的数据 -> 不同的硬件可能具有不同的字节序-> 字节序很重要。 - Sergio Ayestarán
1
这个问题涉及到C语言中的字节序,因此使用了C代码和标签。在标准C中,你不能直接访问特定的位。唯一的访问方式是通过移位、位运算和位域。标准规定数字的最高位应该被视为“第一位”。翻译人员需要确保无论底层硬件的位顺序如何(如果适用),都要遵守这个规定。位域可以从任一端开始,但结果值仍然是最高位优先。网络和通信协议可能以最低位优先传输,但这并不意味着它们在C中存储或访问的方式也是如此。 - jerry
这个答案是完全错误的。请参考https://dev59.com/lnRA5IYBdhLWcg3wsgBP和Deepu在下面的回答。作为一个概念,字节序通常不涉及位的顺序,但某些实现可能会根据字节序翻转位顺序,仅出于自己的判断。 - OldPeculier
哦,主啊,首先:问题在于为什么字节序在位内部很重要,如果你不考虑字节序处理低级硬件,无论你认为什么或者标签是什么,你的代码都不会工作。第二,谢谢,那个人说的和我一样,这不是关于C编译器的讨论,正如我所说,编译器必须在不同的硬件上具有相同的行为,但如果你的程序与另一个硬件接口(即不是你正在开发的PC)交互,在某些情况下需要考虑字节序。 - Sergio Ayestarán

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接