位运算符解释

explanation on bitwise operators

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

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

如果我使用它,我会得到正确的类型(IPv4 为 0x0800),并且可以使用它来比较打印输出是 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 类型。这就是为什么我首先需要比较的原因。感谢您就此功能提供任何建议或解释,我们将不胜感激。谢谢

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 处的数据的大端值(网络约定)。两者在您的情况下是等效的,尽管后者更便于将值作为一个整体进行比较。

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

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

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

所以在移动 packet_data[12] 中的值后,将其键入 0x0800 (100000000000) 的唯一方法是 packet_data[13] 看起来像 0x0800 或0x0000:

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

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

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

输出

0x800
0x0800
0x0000

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

| packet_data[13] 获取第二个以太网类型八位字节并将其与前一个 16 位字按位或运算。

然后您可以将其与 IPv4 的 0x0800 或 IPv6 的 0x86DD 进行比较;在 https://en.wikipedia.org/wiki/EtherType#Examples

上查看更完整的列表

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