Skip to content

Instantly share code, notes, and snippets.

@ecoshub
Last active December 9, 2023 18:27
Show Gist options
  • Star 17 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save ecoshub/5be18dc63ac64f3792693bb94f00662f to your computer and use it in GitHub Desktop.
Save ecoshub/5be18dc63ac64f3792693bb94f00662f to your computer and use it in GitHub Desktop.
golang integer to byte array and byte array to integer function
package main
import (
"fmt"
"unsafe"
)
func main(){
// integer for convert
num := int64(1354321354812)
fmt.Println("Original number:", num)
// integer to byte array
byteArr := IntToByteArray(num)
fmt.Println("Byte Array", byteArr)
// byte array to integer again
numAgain := ByteArrayToInt(byteArr)
fmt.Println("Converted number:", numAgain)
}
func IntToByteArray(num int64) []byte {
size := int(unsafe.Sizeof(num))
arr := make([]byte, size)
for i := 0 ; i < size ; i++ {
byt := *(*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(&num)) + uintptr(i)))
arr[i] = byt
}
return arr
}
func ByteArrayToInt(arr []byte) int64{
val := int64(0)
size := len(arr)
for i := 0 ; i < size ; i++ {
*(*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(&val)) + uintptr(i))) = arr[i]
}
return val
}
@andreapavoni
Copy link

I've copy-pasted the gist into the playground, it worked https://go.dev/play/p/o76zx3Z4O-k

@humsie
Copy link

humsie commented Mar 17, 2022

After some further searching I found out that we are both right (and wrong).
There are 2 ByteOrder apparently : LittleEndian and BigEndian (I only used BigEndian before).
https://pkg.go.dev/encoding/binary#pkg-examples

This gist does LittleEndian, and with my "fix" it does BigEndian.
So check and use what you need.

https://go.dev/play/p/jdXgbSNoZB8

@ecoshub
Copy link
Author

ecoshub commented Mar 23, 2022

@humsie Sorry for delayed response. Yes this gist is for little endian encoding :) But if you are using this for data transfer no mater which encoding you use unless you decode and encode with same algorithm

@stopcenz
Copy link

stopcenz commented Aug 11, 2022

An option without using loops is possible:

func IntToByteArray(i int64) []byte {
	var b []byte
	sh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
	sh.Len = 8
	sh.Cap = 8
	sh.Data = uintptr(unsafe.Pointer(&i))

	return b[:]
}

func ByteArrayToInt(b []byte) int64 {
	return *(*int64)(unsafe.Pointer(&b[0]))
}

Are there any disadvantages other than the need to take into account the peculiarities of the GC?

@ecoshub
Copy link
Author

ecoshub commented Aug 14, 2022

I don't know about garbage collectors behavior but your suggestion is much more memory friendly and much more faster.

"Thats the way" 😄

goos: darwin
goarch: amd64
pkg: test/stable
cpu: Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
Benchmark_Itob-16       83581489                14.31 ns/op            8 B/op          1 allocs/op
Benchmark_Itob_2-16     99950498                11.23 ns/op            8 B/op          1 allocs/op
Benchmark_Btoi-16       469129642                2.436 ns/op           0 B/op          0 allocs/op
Benchmark_Btoi_2-16     1000000000               0.4494 ns/op          0 B/op          0 allocs/op
PASS
ok      test/stable     5.552s

NOTE: *_2 is @stopcenz 's suggestion.

@v0nc
Copy link

v0nc commented Sep 8, 2022

I wrote this not too long ago. Also as far as I know none of the examples above are specifically little- or big endian. This depends on your CPU and could (in theory) result in a big-endian byte array. Please correct me if I'm wrong tho ^^

func ItoBSlice(i int) []byte {
	data := *(*[unsafe.Sizeof(i)]byte)(unsafe.Pointer(&i))
	return data[:]
}

@ecoshub
Copy link
Author

ecoshub commented Sep 11, 2022

Hi @pyglue. I wrote for a custom network protocol. It use same encoder and decoder functions so endianness is not a problem. Also I love your method. I am gonna add your method to same benchmark below as "*_3" later.

@The-Lumberjack
Copy link

Verify Github on Galxe. gid:pGf2Haut6ocx4c3U6YFF6F

@The-Lumberjack
Copy link

gid:pGf2Haut6ocx4c3U6YFF6F

@ntsd
Copy link

ntsd commented Sep 13, 2022

Hi @ecoshub Can I use int instead of int64? and it will be fixed bytes size?

@ecoshub
Copy link
Author

ecoshub commented Sep 13, 2022

Ofcourse!. I cant see any problem with this. But remember its a 2.5 years old snippet :)) Even I dont like this code. You can use @stopcenz or @pyglue s snippets They are much more efficent. @stopcenz snippet is already int64

https://gist.github.com/ecoshub/5be18dc63ac64f3792693bb94f00662f?permalink_comment_id=4264235#gistcomment-4264235

@v0nc
Copy link

v0nc commented Sep 16, 2022

Hi @ecoshub Can I use int instead of int64? and it will be fixed bytes size?

Int isn't really a fixed size. On a 64bit system int is an int64 while on a 32bit system it will be an int32. So depending which system you compile your code for, you will end up with a different result.

@manosriram
Copy link

Do not use unsafe in production though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment