【问题标题】:GoLang bitwise calculationGoLang 逐位计算
【发布时间】:2015-02-11 21:43:56
【问题描述】:

我有一个缓冲区:

buffer := bytes.NewBuffer([]byte{
        0x85, 0x02, 0xFF, 0xFF,
        0x00, 0x01, 0x00, 0x02,
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x01,
        0x00, 0x00, 0x00, 0x03,
        0x41, 0x42, 0x43,
    })

我正在尝试返回缓冲区的 int 值[8:24] 我明白了

[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1]

不知道如何转移这么大的部分。的字节。

对此很陌生。任何帮助都会很棒。我最初的方法是

requestid := (uint64(buffer.Bytes()[8]&0xff)<<24 + uint64(buffer.Bytes()[9]&0xff)<<16 + uint64(buffer.Bytes()[10]&0xff)<<8 + uint64(buffer.Bytes()[11]&0xff.....)))

但这变得乏味,我知道必须有一个更简单的方法。

【问题讨论】:

  • 与直接使用 []byte 切片相比,它位于 bytes.Buffer 中是否有原因?
  • 这就是它的传递方式。 ..但要保持这个完整的循环,你是什么意思?有没有更好的办法?
  • 这不是缓冲区本身,而是您在requestId = 部分中使用它的方式。请参阅下面的答案。

标签: go bitwise-operators


【解决方案1】:

您必须进行手动位移和 OR'ing,但可以通过删除所有 buffer.Bytes() 调用来清理您的代码。

您也不需要&amp;0xff 部分。 n&amp;0xff 所做的是清除 0-255 范围之外的所有位。由于缓冲区中的每个值都已经是一个字节(0-255),因此这些操作根本不执行任何操作。如果我们想做22 &amp; 255,我们会得到以下结果:

    Hexadecimal   | Decimal     | Binary
    --------------|-------------|----------------------
x   0x16          | 22          | 00010110
y   0xff          | 255         | 11111111
    --------------|-------------|---------------------- AND (&)
    0x16          | 22          | 00010110 = x

如您所见,该操作完全没有效果。将x 替换为任何8 位值,您将看到相同的结果。 x &amp; 0xff 的结果总是x

此外,当您分配给 requestId 时,您首先要移位 24 位。这告诉我你正在读取一个 32 位整数。那为什么还要继续读取超过 32 位的值并将其全部转换为 64 位整数?

如果您在 Big Endian 中读取 64 位 int,请尝试以下操作:

data := buf.Bytes()[8:]
requestid := uint64(data[0])<<56 | uint64(data[1])<<48 |
    uint64(data[2])<<40 | uint64(data[3])<<32 |
    uint64(data[4])<<24 | uint64(data[5])<<16 |
    uint64(data[6])<<8 | uint64(data[7])

如果您在 Little Endian 中读取 64 位 int,请尝试以下操作:

data := buf.Bytes()[8:]
requestid := uint64(data[7])<<56 | uint64(data[6])<<48 |
    uint64(data[5])<<40 | uint64(data[4])<<32 |
    uint64(data[3])<<24 | uint64(data[2])<<16 |
    uint64(data[1])<<8 | uint64(data[0])

如果您在 Big Endian 中读取 32 位 int,请尝试以下操作:

data := buf.Bytes()[8:]
requestid := uint32(data[0])<<24 | uint32(data[1])<<16 |
    uint32(data[2])<<8 | uint32(data[3])

如果您在 Little Endian 中读取 32 位 int,请尝试以下操作:

data := buf.Bytes()[8:]
requestid := uint32(data[3])<<24 | uint32(data[2])<<16 |
    uint32(data[1])<<8 | uint32(data[0])

二进制包

或者,您可以使用encoding/binary 包:

var value uint64
err := binary.Read(buf, binary.LittleEndian, &value)
....

【讨论】:

  • 这很有意义。谢谢你。几个问题。
  • encoding/binary 具有读取 uint 的特殊方法,请参见此处:play.golang.org/p/CC9HeZAvRj。它会比binary.Read 更快,因为它避免使用反射。
  • 我现在真的明白了。感谢您的帮助。 >> 我提供的缓冲区带有一个关于值“应该”返回什么的键(根据提供的框架)。最后 RequestID 应该 == 1 。当我运行你的代码时,它只返回 0。在@logiraptors 代码中,他使用 [16:24] 的切片并返回 1。当我向领导询问 Big Endian 或 Little Endian 时,他说没关系. (这里是小开发者)
  • 整数以大端或小端存储在内存中,具体取决于您是在 linux、windows、OSX 等上运行程序。因此,16 位值 1234 可能表示为字节0x04 0xd20xd2 0x04。根据您解释字节的方式,您会得到123453764。有一个普遍接受的约定,即通过网络发送的数据始终以 Big Endian 编码。但最好确保是这种情况。
猜你喜欢
  • 2021-11-30
  • 1970-01-01
  • 2013-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-22
  • 2018-08-30
相关资源
最近更新 更多