无符号整数溢出

zla*_*ski 2 go

关于无符号整数溢出的规范说:

对于无符号整数值,操作+, - ,*和<<以2n为模计算,其中n是无符号整数类型的位宽.松散地说,这些无符号整数运算在溢出时丢弃高位,程序可能依赖于''环绕''.

我尝试测试它,但结果不一致 - http://play.golang.org/p/sJxtSHbigT:

package main

import "fmt"

func main() {
    fmt.Println("test")
    var num uint32 = 1 << 35
}
Run Code Online (Sandbox Code Playgroud)

这给出了错误:

prog.go:7: constant 34359738368 overflows uint32
 [process exited with non-zero status]
Run Code Online (Sandbox Code Playgroud)

但根据规范应该没有错误,而是我应该看到0.

小智 6

您引用的规范特指"操作+, - ,*和<<"的结果.您正在尝试定义常量,而不是查看其中一个操作的结果.

您也不能将这些超大值用于这些操作的输入.编译器不会为您包装任何值; 这只是那些操作的运行时行为.

package main

import "fmt"

func main() {
    var num uint32 = 1 + 1 << 35
    fmt.Printf("num = %v\n", num)
}
Run Code Online (Sandbox Code Playgroud)
prog.go:6: constant 34359738369 overflows uint32
 [process exited with non-zero status]
Run Code Online (Sandbox Code Playgroud)

这是一个有趣的例子.

var num uint32 = (1 << 31) + (1 << 31)
fmt.Printf("num = %v\n", num)
Run Code Online (Sandbox Code Playgroud)
prog.go:6: constant 4294967296 overflows uint32
 [process exited with non-zero status]
Run Code Online (Sandbox Code Playgroud)

在这种情况下,编译器会尝试(1 << 31) + (1 << 31)在编译时进行求值4294967296,生成常量值,该值太大而不适合.

var num uint32 = (1 << 31)
num += (1 << 31)
fmt.Printf("num = %v\n", num)
Run Code Online (Sandbox Code Playgroud)
num = 0
Run Code Online (Sandbox Code Playgroud)

在这种情况下,添加是在运行时执行的,并且值会像您期望的那样回绕.