2013-07-09 9 views
8

big.NewInt(int64(e))。バイト(int)をバイト配列に変換するためのバイト()。 これを行うもっとエレガントな方法はありますか?編集go32でint32をバイト配列に変換する

exp 65537 
b: BigEndian.PutUint32 00010001 (Bad) AAEAAQ 
b2: BigEndian.PutUint32 010001 (Good) AQAB 
b4: big.NewInt(int64(e)).Bytes() 010001 (Good) AQAB 

exp 1 
b: BigEndian.PutUint32 00000001 (Bad) AAAAAQ 
b2: BigEndian.PutUint32 01 (Good) AQ 
b4: big.NewInt(int64(e)).Bytes() 01 (Good) AQ 

exp 1000000 
b: BigEndian.PutUint32 000f4240 (Bad) AA9CQA 
b2: BigEndian.PutUint32 0f4240 (Good) D0JA 
b4: big.NewInt(int64(e)).Bytes() 0f4240 (Good) D0JA 

::私はAQABが電子

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

const e = 65537 

func base64Encode(b []byte) string { 
    return strings.TrimRight(base64.StdEncoding.EncodeToString(b), "=") 
} 

func main() { 
    fmt.Printf("exp %d\n", e) 

    b := make([]byte, 4) 
    binary.BigEndian.PutUint32(b, e) 
    fmt.Printf("b: BigEndian.PutUint32 %x (Bad) %s\n", b, base64Encode(b)) 

    b2 := make([]byte, 4) 
    binary.BigEndian.PutUint32(b2, e) 
    for i := range b2 { 
    if b2[i] != 0 { 
    b2 = b2[i:] 
    break 
    } 
    } 
    fmt.Printf("b2: BigEndian.PutUint32 %x (Good) %s\n", b2, base64Encode(b2)) 

    b4 := big.NewInt(int64(e)).Bytes() 
    fmt.Printf("b4: big.NewInt(int64(e)).Bytes() %x (Good) %s\n", b4, base64Encode(b4)) 
} 

出力のbase64でエンコードされた値であることを期待

私はB2およびB4ベンチマークました:

b2 1000000000   68.1 ns/op   8 B/op   1 allocs/op 
b4 200000000   248 ns/op   90 B/op   3 allocs/op 

私はそれが不足し、ビット単位の数学であれば、私は、あなたの最初のオプションは常にencoding/binaryを使用するべきだと思いますし、タスクのこの種のために今...

答えて

5

用B2を使用します。しかし、いくつかのケースでは、データをコピーするオーバーヘッドが大きすぎる、またはこれら安全ソリューションは遅すぎる:

私はそれはエレガントなあなたは非常に迅速にこれを行うに行くのunsafereflect *パッケージを使用することができます呼び出さないだろうが。これはデータをコピーしないことを覚えておいてください。むしろ、それはあなたに別の "見解"を与えます。安全でないということは、あなたが非常に注意する必要があることを意味します(ユニットテストとコードレビュー)。Goのmemory safetyを壊していることに注意してください。しかし、実行速度が支配的な懸念事項であり、あなたのチームがunsafeに合意した場合、unsafeはめったにうまくいかない場合があります。

const BYTES_IN_INT32 = 4 

func UnsafeCaseInt32ToBytes(val int32) []byte { 
    hdr := reflect.SliceHeader{Data: uintptr(unsafe.Pointer(&val)), Len: BYTES_IN_INT32, Cap: BYTES_IN_INT32} 
    return *(*[]byte)(unsafe.Pointer(&hdr)) 
} 

func UnsafeCastInt32sToBytes(ints []int32) []byte {   
    length := len(ints) * BYTES_IN_INT32 
    hdr := reflect.SliceHeader{Data: uintptr(unsafe.Pointer(&ints[0])), Len: length, Cap: length} 
    return *(*[]byte)(unsafe.Pointer(&hdr)) 
} 

注:定数ではなくSizeOfを使用します。私はより良い定数が好きです。

アップデート:ここにいくつかのベンチマーク結果は次のとおりです。

BenchmarkB2  20000000  88.7 ns/op 
BenchmarkB4  5000000  309 ns/op 
BenchmarkUnsafe 1000000000 2.25 ns/op 
+5

だけでなく 'unsafe'ブレークメモリの安全性は、それはエンディアンの問題を紹介しません。 –

+0

@larsmans:ビットシフトするものはあなた自身です。さらに、 'encoding/binary'自体はエンディアンに対応しています(http://golang.org/pkg/encoding/binary/#pkg-variables)。 – voidlogic

+7

いいえ、シフトが安全です。 'x >> 24'はエンディアンに関係なく、' x'の上位8ビットを取得します。 –

関連する問題