我最近阅读了effective_go文档,在阅读 Print 部分时感到震惊:
var x uint64 = 1<<64 - 1
fmt.Printf("%d %x; %d %x\n", x, x, int64(x), int64(x))
打印
18446744073709551615 ffffffffffffffff; -1 -1
作为一名C程序员,%x int64(x)
的预期输出也应该是ffffffffffffffff
,所以上面的输出对我来说是不合理的,有人能说出原因吗?
答案 0 :(得分:3)
这里的行为与C不同,例如。整数的%x
动词意味着使用十六进制(基数16)表示格式化数字的值,而不是其存储器表示(这将是2的补码)。对于二进制%b
和八进制表示的%o
也是如此。
对于-255
这样的负数,其base16表示为-ff
。
Go对类型严格,你必须要明确。如果传递有符号整数,则将其格式化为有符号整数。如果要将其打印为无符号值,则必须将其显式转换为无符号值,如下例所示:
i := -1 // type int
fmt.Printf("%d %x %d %x", i, i, uint(i), uint(i))
输出(在Go Playground上尝试):
-1 -1 4294967295 ffffffff
请注意,将有符号值转换为无符号版本(相同大小)时,它不会更改内存表示的类型,因此转换后的值(无符号结果)将是已签名的2的补码值。
至于为什么这是负数的默认值,请阅读Rob Pike here给出的推理:
为什么这不是默认[无符号格式]?因为如果是的话,就没有办法将某些东西打印为负数,正如你所看到的那样,这是一个更短的表示。换句话说,%b%o%d%x all同样对待他们的论点。
您可以在此相关问题中查看此操作的实现方式/位置:Golang: Two's complement and fmt.Printf
答案 1 :(得分:3)
C编程语言,第二版
x,X int;无符号十六进制数(没有前导0x或0X), 使用abcdef或ABCDEF表示10,...,15。
x,X unsigned int;无符号十六进制表示法(没有前导0x 或0X),使用abcdef表示0x或ABCDEF表示0X。
GNU C Library Reference Manual,Version 2.27
'%x','%X'将整数打印为无符号十六进制数。 '%X' 使用小写字母,'%X'使用大写字母。
我感到震惊 - 发现这里正在进行整数转换!
在C中,隐含的转换比比皆是。在Go中,按设计,转换是明确的。
在C中,printf隐式将有符号整数转换为格式为%x
的无符号整数。转而fmt.Printf
没有。
按照设计,Go不是C. Go确实与C有相似之处,这可能会让人不知所措。
答案 2 :(得分:0)
int64(math.MaxUint64)
溢出int64
:
package main
import (
"fmt"
"math"
)
func main() {
var x uint64 = 1<<64 - 1
fmt.Printf("%v\n", math.MaxUint64 == x) // true
var y int64 = 1<<63 - 1
fmt.Printf("%v\n", math.MaxInt64 == y) // true
var z int64 = int64(x) // -1
fmt.Printf("%v\n", z)
}
游乐场:https://play.golang.org/p/J6buiaaZcFt
请参阅https://golang.org/pkg/math/#pkg-constants和https://play.golang.org/p/iul2dgRbK2E