16

すべて。非常に奇妙な問題に直面しています。(私が眠るべき時はずっと過ぎているかもしれません、そして私は何か明白なものを見落としています。)

[]byteいくつかの16進デコードの結果として、長さが8のaがあります。使用するにはを作成する必要がありuint64ます。binary.Uvarint()、fromを使用してみencoding/binaryましたが、配列の最初のバイトしか使用していないようです。次の例を考えてみましょう。

package main

import (
    "encoding/binary"
    "fmt"
)

func main() {
    array := []byte{0x00, 0x01, 0x08, 0x00, 0x08, 0x01, 0xab, 0x01}
    num, _ := binary.Uvarint(array[0:8])
    fmt.Printf("%v, %x\n", array, num)
}

こちらはplay.golang.orgにあります。

それが実行されると、16進数では。である必要がありますが、numとして表示されます。さらに、から2番目の値を取得した場合、それはバッファから読み取られたバイト数です。これは、実際には1ですが、私の知る限り、8である必要があります。0000108000801ab01binary.Uvarint()

私はこれを間違って解釈していますか?もしそうなら、私は代わりに何を使うべきですか?

ありがとう、みなさん。:)

4

3 に答える 3

19

必要な関数を使用していない関数を使用してデコードしています:

バリントは、1つ以上のバイトを使用して整数をエンコードする方法です。絶対値が小さい数値は、バイト数が少なくなります。仕様については、 http://code.google.com/apis/protocolbuffers/docs/encoding.htmlを参照してください。

これは標準のエンコーディングではなく、非常に具体的な可変バイト数のエンコーディングです。そのため、値が0x080未満の最初のバイトで停止します。

Stephenが指摘したように、binary.BigEndianとbinary.LittleEndianは、直接デコードするための便利な関数を提供します。

type ByteOrder interface {
    Uint16([]byte) uint16
    Uint32([]byte) uint32
    Uint64([]byte) uint64
    PutUint16([]byte, uint16)
    PutUint32([]byte, uint32)
    PutUint64([]byte, uint64)
    String() string
}

だからあなたは使うかもしれません

package main

import (
    "encoding/binary"
    "fmt"
)

func main() {
    array := []byte{0x00, 0x01, 0x08, 0x00, 0x08, 0x01, 0xab, 0x01}
    num := binary.LittleEndian.Uint64(array)
    fmt.Printf("%v, %x", array, num)
}

または(パニックになる代わりにエラーをチェックしたい場合は、直接的な解決策でこの問題を指摘してくれたjimtに感謝します):

package main

import (
    "encoding/binary"
    "bytes"
    "fmt"
)

func main() {
    array := []byte{0x00, 0x01, 0x08, 0x00, 0x08, 0x01, 0xab, 0x01}
    var num uint64
    err := binary.Read(bytes.NewBuffer(array[:]), binary.LittleEndian, &num)
    fmt.Printf("%v, %x", array, num)
}
于 2012-12-01T08:45:57.800 に答える
2

バイト順序を気にしない場合は、次のことを試すことができます。

arr := [8]byte{1,2,3,4,5,6,7,8}
num := *(*uint64)(unsafe.Pointer(&arr[0]))

http://play.golang.org/p/aM2r40ANQC

于 2016-04-14T04:10:21.223 に答える
1

Uvarintの関数を見ると、期待したほど単純な変換ではないことがわかります。

正直なところ、私はそれがどのようなバイトフォーマットを期待するのかまだ理解していません(編集を参照)。

しかし、自分で書くのは簡単です。

func Uvarint(buf []byte) (x uint64) {
    for i, b := range buf {
        x = x << 8 + uint64(b)
        if i == 7 {
            return
        }
    }
    return
}

編集

バイト形式は私がよく知っているものではありません。これは、各バイトの最上位ビットがフラグである可変幅エンコーディングです。
0に設定すると、そのバイトはシーケンスの最後になります。
1に設定すると、エンコードは次のバイトに進む必要があります。

uint64値の作成には、各バイトの下位7ビットのみが使用されます。最初のバイトはuint64の下位7ビットを設定し、次のバイトは8〜15を設定します。

于 2012-12-01T08:38:28.200 に答える