位操作golang

Bit manipulation golang

我正在查看包含以下内容的代码库:


const IdLength = 20

type NodeID [IdLength]byte

func (node NodeID) PrefixLen() (ret int) {
  for i := 0; i < IdLength; i++ {
    for j := 0; j < 8; j++ {
      if (node[i] >> uint8(7 - j)) & 0x1 != 0 {
        return i * 8 + j;
      }
    }
  }
  return IdLength * 8 - 1;
}

我不太明白这里发生了什么。谁能举个例子给我解释一下?

这将可变数量的字节作为输入,这些字节实际上被视为位。它 return 是字节流中前导 0 位的数量。假设您有这些字节:

0x00 0x00 0x05

二进制文件看起来像这样

00000000 00000000 00000101

表示函数returns 8+8+5 = 21.

i作为变量的外循环遍历所有字节,以j作为变量的内循环遍历该字节中的所有位。它从顶部移动第 j 位,向下移动到最低位,二进制和 (&) 与 0x01 屏蔽除最低位之外的所有内容,然后 != 0 询问该位是否是 1 在这种情况下,我们位于 0 前缀和 return 结果的末尾。

如果在函数末尾没有早期的 return,所有字节都是 0 所以它 return 是那个值。由于某种原因,这种特殊情况不是 return 208,而是 208-1。我猜这是特定于应用程序的。我本来希望它 return 全部为零,但它 return 少了一个。

这是一个代码示例,输出为注释:

package main

import "fmt"

func main() {
    fmt.Println(NodeID{0xFF}.PrefixLen()) // 0
    fmt.Println(NodeID{0x7F}.PrefixLen()) // 1
    fmt.Println(NodeID{0x3F}.PrefixLen()) // 2
    fmt.Println(NodeID{0x1F}.PrefixLen()) // 3
    fmt.Println(NodeID{0x0F}.PrefixLen()) // 4
    // ...
    fmt.Println(NodeID{0x00, 0x00, 0x05}.PrefixLen()) // 21
    // ...
    fmt.Println(NodeID{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}.PrefixLen()) // 159
    fmt.Println(NodeID{}.PrefixLen()) // 159
}

const IdLength = 20

type NodeID [IdLength]byte

func (node NodeID) PrefixLen() (ret int) {
    for i := 0; i < IdLength; i++ {
        for j := 0; j < 8; j++ {
            if (node[i]>>uint8(7-j))&0x1 != 0 {
                return i*8 + j
            }
        }
    }
    return IdLength*8 - 1
}