Converting between a 3-byte slice and signed integer type

192 views Asked by At

I have a slice consisting of 3 bytes (ordered in LE) that is representing a signed integer, and I want to convert it to any of the integer types, preferably int32, and then back to itself.

b := []byte{0x01, 0x00, 0x80}

I tried to do that using big.Int, but it seemed like its SetBytes() and Bytes() methods only work for unsigned integer types, regardless of that a big.Int instance can also store signed integer types.

Here is a Python equivalent of what I’m trying to do:

b = b"\x01\x00\x80"
i = int.from_bytes(b, "little", signed=True)
b_again = int.to_bytes("little", signed=True)

Edit: This question is not a duplicate of Go []byte to Little/Big-Endian Signed Integer or Float?. I have tried applying the answers there, but their results weren’t expected. See my first comment.

2

There are 2 answers

0
rocka2q On BEST ANSWER

I have a slice consisting of 3 bytes (ordered in LE) that is representing a signed integer, and I want to convert it to any of the integer types, preferably int32, and then back to itself.


package main

import "fmt"

func ByteLE3ToInt24(b []byte) int32 {
    i := uint32(b[0])<<8 | uint32(b[1])<<16 | uint32(b[2])<<24
    return int32(i) >> 8
}

func Int24ToByteLE3(i int32) []byte {
    return []byte{byte(i), byte(i >> 8), byte(i >> 16)}
}

func main() {
    b := []byte{0x01, 0x00, 0x80} // Negative
    fmt.Println(b)
    fmt.Println(ByteLE3ToInt24(b))
    fmt.Println(Int24ToByteLE3(ByteLE3ToInt24(b)))
    fmt.Println()
    b = []byte{0x01, 0x00, 0x00} // Positive
    fmt.Println(b)
    fmt.Println(ByteLE3ToInt24(b))
    fmt.Println(Int24ToByteLE3(ByteLE3ToInt24(b)))
}

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

[1 0 128]
-8388607
[1 0 128]

[1 0 0]
1
[1 0 0]
1
gonutz On

Little-Endian means that the number 0x01020304 is encoded as the byte squence []byte{4, 3, 2, 1}.

Your example number has three bytes, so I assume that you mean 0x00010080 (left-filled with a zero-byte).

There is a type encoding/binary.ByteOrder with the two instances LittleEndian and BigEndian which provide functions to convert to and from bytes:

package main

import (
    "encoding/binary"
    "fmt"
)

func main() {
    var b [4]byte
    binary.LittleEndian.PutUint32(b[:], 0x00010080)
    i32 := int32(binary.LittleEndian.Uint32(b[:]))
    fmt.Println(b)   // Prints [128 0 1 0].
    fmt.Println(i32) // Prints 65664 (which is 0x00010080).
}