在Go中将int32转换为字节数组

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

Converting int32 to byte array in go

问题

我正在使用big.NewInt(int64(e)).Bytes()将int32转换为字节数组。
有没有更优雅的方法来做这个?

我期望AQAB是e的base64编码值

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

输出:

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

编辑:

我对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

我现在将使用b2...

英文:

I am using big.NewInt(int64(e)).Bytes() to convert an int32 to a byte array.
Is there a more elegant way to do this?

I expect AQAB to be the base64 encoded value of e

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

Output:

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

Edit:

I've benchmarked b2 and b4:

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

I'll use b2 for now...

答案1

得分: 5

对于这种任务,我认为你的首选应该始终使用encoding/binary,如果不够的话,可以使用位运算。然而,在某些情况下,复制数据的开销太大,或者这些“安全”的解决方案太慢:

虽然我不认为它很优雅,但你可以使用Go的unsafereflect包来快速完成这个任务。只需记住,这不是复制数据,而是给你提供了另一个“视图”。而且,由于它是不安全的,所以你需要非常小心(你好单元测试和代码审查),并且要记住你正在破坏Go的内存安全性。然而,当执行速度是主要关注点,并且你的团队同意使用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
英文:

For this kind of task I think your first options should always be using encoding/binary and, if that is insufficient, bitwise math. However, in some cases the overhead of copying data is too large or these safe solutions are too slow:

While I would not call it elegant you can use Go's unsafe and reflect* packages to do this very quickly. Just remember, this does not copy the data; rather, it just gives you another "view" of it. And being well- unsafe means that you need to be very careful- (hello units tests and code review) and keep in mind you are breaking Go's memory safety. However, when execution speed is the dominating concern and your team agrees unsafe is warranted, unsafe can seldom be beat.

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

*Note: You may want to use SizeOf rather than a constant. I like the constant better.

Update: here are some benchmark results:

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

答案2

得分: -1

这是最直接(也是最短(也是最安全)(也可能是最高效))的方法:

buf.Bytes() 是字节切片类型。

	var val uint32 = 42
	buf := new(bytes.Buffer)
	err := binary.Write(buf, binary.LittleEndian, val)
	if err != nil {
		fmt.Println("binary.Write 失败:", err)
	}
	fmt.Printf("% x\n", buf.Bytes())
英文:

This is the most straight forward (and shortest (and safest) (and maybe most performant)) way:

buf.Bytes() is of type bytes slice.

	var val uint32 = 42
	buf := new(bytes.Buffer)
	err := binary.Write(buf, binary.LittleEndian, val)
	if err != nil {
		fmt.Println("binary.Write failed:", err)
	}
	fmt.Printf("% x\n", buf.Bytes())

huangapple
  • 本文由 发表于 2013年7月9日 10:35:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/17539001.html
匿名

发表评论

匿名网友

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

确定