GoLang 位运算计算

huangapple go评论81阅读模式
英文:

GoLang bitwise calculation

问题

我有一个缓冲区:

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,
})

我试图返回buffer[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.....)))

但这变得很繁琐,我知道肯定有更简单的方法。

英文:

I have a buffer :

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,
})

I am trying to return the int value of buffer[8:24]
I get

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

Not sure how to shift such a large section. of the byte.

new to this. Any help would be great. my initial approach was

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

but this got tedious, and I know there has to be an easier way.

答案1

得分: 3

你需要进行手动的位移和按位或操作,但是你的代码可以通过删除所有那些buffer.Bytes()调用来进行清理。

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

    十六进制   | 十进制     | 二进制
    --------------|-------------|----------------------
x   0x16          | 22          | 00010110
y   0xff          | 255         | 11111111
    --------------|-------------|---------------------- AND (&)
    0x16          | 22          | 00010110 = x

如你所见,这个操作根本没有任何效果。将x替换为任何8位值,你将得到相同的结果。x & 0xff的结果始终是x

此外,当你给requestId赋值时,你从24位开始进行位移。这告诉我你正在读取一个32位整数。那么为什么你继续读取超过32位的值,并将其全部转换为64位整数呢?

如果你正在以大端字节序读取64位整数,请尝试以下代码:

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])

如果你正在以小端字节序读取64位整数,请尝试以下代码:

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])

如果你正在以大端字节序读取32位整数,请尝试以下代码:

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

如果你正在以小端字节序读取32位整数,请尝试以下代码:

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)
....
英文:

You have to do the manual bit shifting and OR'ing, but your code can be cleaned up by removing all those buffer.Bytes() calls.

You also do not need the &amp;0xff parts. What n&amp;0xff does, is clear out all bits outside of the 0-255 range. Since each value in the buffer is already a byte (0-255), these operations do nothing at all. If we want to do 22 &amp; 255, we get the following:

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

As you can see, the operation has no effect at all. Replace x with any 8-bit value and you will see the same result. The outcome of x &amp; 0xff is always x.

Additionally, when you assign to the requestId, you start by shifting by 24 bits. This tells me you are reading a 32-bit integer. Why then do you continue reading values beyond 32 bits and converting it all to a 64 bit integer?

If you are reading a 64-bit int in Big Endian, try this:

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

If you are reading a 64-bit int in Little Endian, try this:

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

If you are reading a 32-bit int in Big Endian, try this:

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

If you are reading a 32-bit int in Little Endian, try this:

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

binary package

Alternatively, you can use the encoding/binary package:

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

huangapple
  • 本文由 发表于 2015年2月12日 05:43:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/28465098.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定