代码之家  ›  专栏  ›  技术社区  ›  Mike1982

位运算符说明

  •  2
  • Mike1982  · 技术社区  · 7 年前

    我在网上找到了这段代码,它是我项目的一部分,但我不知道为什么。我不想在不了解它的功能的情况下使用它。

    type = (packet_data[12] << 8) | packet_data[13];
    

    如果我使用它,我会得到正确的类型(0x0800表示IPv4),并可以使用它在打印时进行比较,无论是IPv4还是IPv6。如果我不使用它并尝试以下操作:

    if(packet_data[12] == 08 && packet_data[13] == 00)
        print out IPv4
    

    它不起作用(编译错误)。

    如果我只是打印出如下值

    printf"%02X", packet_data[12];
    printf"%02X", packet_data[13];
    

    它以0800的形式打印出正确的值,但我需要打印出它是IPv4类型。这就是为什么我首先需要比较。感谢您对这一功能的任何建议或解释,我们将不胜感激。谢谢

    3 回复  |  直到 7 年前
        1
  •  1
  •   Jean-François Fabre    7 年前
    if(packet_data[12] == 08 && packet_data[13] == 00)
    

    编译器将右文字操作数视为八进制文字。

    幸运的是, 8 无法表示八进制数,因此出现编译错误。

    您是指十六进制文字:

    if (packet_data[12] == 0x8 && packet_data[13] == 0x0)
    

    该行:

    (packet_data[12] << 8) | packet_data[13]
    

    重新创建位于偏移12处的数据的大端值(网络约定);13.两者在您的情况下是等效的,尽管后者更便于整体比较值。

        2
  •  0
  •   Zac67    7 年前

    packet_data[12] << 8 取第一个Ethertype八位字节,并将其向左移动8位到16位字的上8位。

    | packet_data[13] 将第二个Ethertype八位字节按位或运算到前一个16位字。

    然后可以将其与 0x0800 对于IPv4或 0x86DD 对于IPv6;在上查看更完整的列表 https://en.wikipedia.org/wiki/EtherType#Examples

    正如已经指出的那样 08 因为数字以开头,所以不起作用 0 表示八进制数,和 8 八进制中不存在。

        3
  •  0
  •   Elfen Dew    7 年前
    type = (packet_data[12] << 8) | packet_data[13];
    

    这个 << 是按位左移。它采用变量的二进制表示,并将其1向左移动,在本例中为8位。

    “0x0800”看起来像 100000000000 二进制格式。因此,为了使0x0800成为类型,它必须在之后看起来像那样 | packet_data[13] . 最后一部分是按位或。如果左侧或右侧的某个位置有1,则会写入1,否则会写入0。

    因此,在移位packet_数据[12]中的值之后,它的唯一方式是0x0800类型( 100000000000 )如果包_数据[13]看起来像0x0800或0x0000:

    type = (0x800)  <==>  ( 100000000000 | 100000000000 )
    type = (0x800)  <==>  ( 100000000000 | 000000000000 )
    

    此外,为了获得 0x 从printf()中,您需要添加 %# 格式说明符。但要获得0x0800,需要指定一个 .04 这意味着包括前导零在内的4个字符。但是,这不会输出 0x 如果类型为0。为此,您需要硬编码文字 0x 转换为printf()。

    printf("%#02x\n", data);
    printf("%#.04x\n", data);
    printf("0x%.04x\n", data=0);
    

    输出

    0x800
    0x0800
    0x0000