Converting Hex to signed Int in Go - go

I want to convert a hex string to a signed integer Value in Go. My input value is "FF60" and I want the output to be "-160". When I use the following function, the result is "65376", which represents the unsigned representation.
value, err := strconv.ParseInt("FF60", 16, 64)
I would have expected the outcome of 65376 when using the ParseUInt function.
Any help would be really appreciated.

The third parameter of strconv.ParseInt() tells the bitsize of the integer you want to parse. 0xff60 parsed as a 64-bit integer is indeed 65376.
You actually want to parse it as a 16-bit integer, so pass 16 as the bitsize. Doing so you will get an error though:
strconv.ParseInt: parsing "FF60": value out of range
Which is true: 0xFF60 (which is 65376) is outside of the valid range of int16 (valid int16 range is [-32768..32767]).
So what you may do is parse it as an unsigned 16-bit integer using strconv.ParseUint(), then convert the result to a signed 16-bit integer:
value, err := strconv.ParseUint("FF60", 16, 16)
fmt.Println(value, err)
fmt.Println(int16(value))
This will output (try it on the Go Playground):
65376 <nil>
-160

Related

Converting between rune and byte (slice)

Go allows conversion from rune to byte. But the underlying type for rune is int32 (because Go uses UTF-8) and for byte it is uint8, the conversion therefore results in a loss of information. However it is not possible to convert from a rune to []byte.
var b byte = '©'
bs := []byte(string('©'))
fmt.Println(b)
fmt.Println(bs)
// Output
169
[194 169]
Working example
Why does Go allow conversion from rune to byte instead of rune to []byte?
Go supports conversion from rune to byte as it does for all pairs of numeric types. It would be a surprising special case if int32 to byte conversion was not allowed.
But the underlying type for rune is int32 (because Go uses UTF-8)
This misses an important detail: rune is an alias for int32. They are the same type.
It's true that the underlying type is rune is int32, but that's because rune and int32 are the same type and the underlying type of a builtin type is the type itself.
The representation of Unicode code points as int32 values is unrelated to UTF-8 encoding.
the conversion therefore results in a loss of information
Yes, conversions between numeric types can result in loss of information. This is one reason why conversions in Go must be explicit.
Note that the statement var b byte = '©' does not do any conversions. The expression '#' is an untyped constant.
The compiler reports an error if the assignment of an untyped constant results in a loss of information. For example, the statement var b byte = '世' causes a compilation error.
All UTF-8 encoding functionality in the language is related to the string type. The UTF-8 aware conversions are all to or from the string type. The []byte(numericType) conversion could be supported, but that would bring UTF-8 encoding outside of the string type.
The Go authors regret including the string(numericType) conversion because it's not very useful in practice and the conversion is not what some people expect. A library function is a better place for the functionality.
Yes it is possible to convert from a rune to []byte (for example via a byte) and back again.
package main
import "fmt"
func main() {
var b byte = '©'
bs := []byte{b}
fmt.Printf("%T %v\n", b, b) // uint8 169
fmt.Printf("%T %v\n", bs, bs) // []uint8 [169]
s := string(bs[0]) // s := string(b) works too.
r2 := rune(s[0]) // r2 := rune(b) works too.
fmt.Printf("%T %v\n", s, s) // string ©
fmt.Printf("%T %v\n", r2, r2) // int32 169
}
The reason for this behaviour is the same reason why it's legal to do
var b int32
b = 1000000
fmt.Printf("%b\n", b)
fmt.Printf("%b", uint8(b))
// Output:
// 11110100001001000000
// 1000000
You should expect the conversion to loose data when you put data of a type with larger memory footprint into one with a smaller memory footprint.
Also, for encoding a rune you can use EncodeRune which indeed uses a []byte.

Cannot convert byte to int in Golang

This is strange but I cannot convert byte value into int.
Here is the code:
fmt.Println("numMsgsByte is:", numMsgsByte)
numMsgsStr := string(numMsgsByte)
fmt.Println("numMsgsStr is:", numMsgsStr)
numMsgs, err = strconv.Atoi(numMsgsStr)
if err != nil {
log.Println("error in msg conversion", err)
return 0
}
The terminal print out:
numMsgsByte is: [5]
numMsgsStr is:
counter.go:51: error in msg conversion strconv.Atoi: parsing "\x05": invalid syntax
What could be wrong here? How can I fix it?
numMsgByte is not a byte, it is a []byte, which contains 5 (not "5"). When you convert it to string using string(numMsgByte), you get a string "\x5".
What you need is: int(numMsgType[0])
The correct way to get an integer out of Redis using redigo would be to just use redis.Int in the first place, instead of using redis.Bytes and trying to convert the result to an int yourself.
In general though, to convert an arbitrary byte array to the integer it represents, you would use the encoding/binary package. You'll need to know some key details about the byte array though:
Does it represent a signed or unsigned value?
Of what width? 32 bit? 64 bit?
Of what byte order? Big-endian? Little-endian?
Are you sure it's represented as an integer, not e.g. a float, or a string representation of a number?
To quote the example from the docs:
b := []byte{0xe8, 0x03, 0xd0, 0x07}
x1 := binary.LittleEndian.Uint16(b[0:])
x2 := binary.LittleEndian.Uint16(b[2:])
fmt.Printf("%#04x %#04x\n", x1, x2)

golang simplejson mustint64 doesn't convert from string to int64

I am using simplejson, and it provides type asserters.
fmt.Printf("%s %s", m.Get("created_time").MustString(), m.Get("created_time").MustInt64())
above code shows this result:
1506259900 %!s(int64=0)
So MustInt64() gives 0 instead of converted Int64 value.
Is it because the 1506259900 is too big to be converted?
Thank for your help!
The original json was:
{"created_time":"1505733738"}
Not
{"created_time":1505733738}
It's originally a STRING, not a NUMBER.
So, when use MustInt64() to that json, it should return 0 because type is not matched.
Right way to treat this is using strconv.
i64, err := strconv.ParseInt(m.Get("created_time").MustString(), 10, 64)
And you'll get what you wanted as i64.

Display base 10 representation of huge hexa string?

Trying to find how to have this hexa string "58068906d6194c6cbda7a6df" into it's base 10 representation.
I tried with this:
i, err := strconv.Parse("58068906d6194c6cbda7a6df", 16, 64)
Obviously I'm getting this error: parsing "58068906d6194c6cbda7a6df"; value out of range
I also need to take the base 10 string representation and get this hexa value back after some processing. i.e.:
base10 := "58068906d6194c6cbda7a6df" => to base 10 string
some processing
hexa := base10 => to base 16 string
Can I use the fmt package to dislpay the base 10? I know that displaying the hexa of a base 10 I could use %x, but what can I do with an existing string?
Thanks for your help, for a reason I cannot understand, I'm unable to find any way to do this.
Your hex value is larger than int64 can hold, so you have to use a big.Int
https://play.golang.org/p/OPPL43u6nB
i := new(big.Int)
i.SetString("58068906d6194c6cbda7a6df", 16)
fmt.Println(i)
To get a hex string representation from a big.Int, you can use the Text method:
hex := i.Text(16)

what's wrong with golang constant overflows uint64

userid := 12345
did := (userid & ^(0xFFFF << 48))
when compiling this code, I got:
./xxxx.go:511: constant -18446462598732840961 overflows int
Do you know what is the matter with this and how to solve it ?
Thanks.
^(0xFFFF << 48) is an untyped constant, which in go is an arbitrarily large value.
0xffff << 48 is 0xffff000000000000. When you negate it, you get -0xffff000000000001 (since with two's complement, -x = ^x + 1, or ^x = -(x + 1)).
When you write userid := 12345, userid gets the type int. Then when you try to and (&) it with the untyped constant -0xffff000000000001 the compiler figures that this constant needs to be an int. At this point, the compiler complains because the value is too large in magnitude to be an int.
If you're trying to get the constant 0x0000ffffffffffff, then you can use 1<<48 - 1, which (if you've got 64-bit ints), will fit. Since your code will never work if int is 32-bits, then you should probably use int64 in your code rather than int to make it portable.
The blog post https://blog.golang.org/constants explains how constants work, and some background on why they are the way they are.
The Go Programming Language Specification
Constants
Numeric constants represent values of arbitrary precision and do not
overflow.
Constants may be typed or untyped.
A constant may be given a type explicitly by a constant declaration or
conversion, or implicitly when used in a variable declaration or an
assignment or as an operand in an expression. It is an error if the
constant value cannot be represented as a value of the respective
type.
An untyped constant has a default type which is the type to which the
constant is implicitly converted in contexts where a typed value is
required, for instance, in a short variable declaration such as i := 0
where there is no explicit type. The default type of an untyped
constant is bool, rune, int, float64, complex128 or string
respectively, depending on whether it is a boolean, rune, integer,
floating-point, complex, or string constant.
Numeric types
int is an implementation-specific size, either 32 or 64 bits.
userid is of type int. For example,
package main
import "fmt"
func main() {
userid := 12345
did := uint64(userid) & ^uint64(0xFFFF<<48)
fmt.Println(userid, did)
}
Output:
12345 12345

Resources