-
-
Save ecoshub/5be18dc63ac64f3792693bb94f00662f to your computer and use it in GitHub Desktop.
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 | |
} |
I've copy-pasted the gist into the playground, it worked https://go.dev/play/p/o76zx3Z4O-k
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.
@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
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?
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.
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[:]
}
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.
Verify Github on Galxe. gid:pGf2Haut6ocx4c3U6YFF6F
gid:pGf2Haut6ocx4c3U6YFF6F
Hi @ecoshub Can I use int instead of int64? and it will be fixed bytes size?
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.
Do not use unsafe in production though.
@ecoshub : How long were the test-Strings in your BtoI tests? ππ»
not only in this part but also in production servers for 4 years π @mwat56
Came across this gist while searching for something similar, and wanted to point out this gist is wrong. The order of the bytes is reversed.
output for
22233
is[217 86 0 0 0 0 0 0]
but should be[0 0 0 0 0 0 86 217]
arr[I]
on Line 27 and 35 should bearr[size - 1 - i]
to reverse through the byte arrayWith those lines fixed the output is correct: