Go acts differently here than C for example. The %x
verb for integers means to format the value of the number using the hexadecimal (base 16) representation, not its memory representation (which would be 2's complement). Same goes for %b
for binary and %o
for octal representation.
For a negative number like -255
, its base16 representation is -ff
.
Go is strict about types, you always have to be explicit. If you pass a signed integer, it will be formatted as a signed integer. If you want to print it as an unsigned value, you have to explicitly convert it to an unsigned value like in this example:
i := -1 // type int
fmt.Printf("%d %x %d %x", i, i, uint(i), uint(i))
Output (try it on the Go Playground):
-1 -1 4294967295 ffffffff
Note that when converting a signed value to its unsigned version (same size) it does not change the memory representation just its type, so the converted value (the unsigned result) will be the 2's complement of the signed value.
As to why this is the default for negative numbers, read the reasoning given by Rob Pike here:
Why is that not the default [the unsigned format]? Because if it were, there would be no way to print something as a negative number, which as you can see is a much shorter representation. Or to put it another way, %b %o %d %x all treat their arguments identically.
You can see how / where this is implemented in this related question: Golang: Two's complement and fmt.Printf