2012-12-01 65 views
9

全部。我遇到了似乎是一個非常奇怪的問題。 (這可能是我應該睡着的時候已經過去了,而且我忽略了一些明顯的東西。)將[8]字節轉換爲uint64

我有一個[]byte,由於十六進制解碼的結果,它的長度爲8。我需要製作一個uint64才能使用它。我嘗試使用binary.Uvarint(),從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) 
} 

Here it is on play.golang.org.

時運行,它會顯示num0,即使在十六進制,它應該是000108000801ab01。此外,如果從binary.Uvarint()獲得第二個值,它是從緩衝區讀取的字節數,據我所知,應該是8,即使它實際上是1.

我解釋這個錯誤嗎?如果是這樣,我應該用什麼來代替?

謝謝,你們都。 :)

回答

15

您使用,它的使用是不是你所需要的一個功能解碼的最低7位:

Varints是一種使用一個或多個字節編碼整數的方法; 具有較小絕對值的數字佔用較少的字節數。 有關規範,請參閱 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) 
} 
+3

你能避免read()和bytes.Buffer通過只是在做'NUM:= binary.LittleEndian.Uint64(陣列)' –

+0

@StephenWeinberg +1我不知道。我更換了我的解決方案以使用您的清潔劑。 –

+2

需要注意的是,如果輸入緩衝區不夠大,無法容納完整請求的數據類型,這些快捷方式將會出現混亂。使用'binary.Read'方法給你一個'error'返回你可以檢查。 – jimt

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,則編碼應該繼續下一個字節。

只有每個字節的低7位用於構建uint64值。第一個字節將設置UINT64,接下來的數據位8-15等