英文:
Overflow of unsigned integers
问题
根据Go语言规范中的说明,对于无符号整数溢出的情况:
- 对于无符号整数值,操作+、-、*和<<会对2的n次方取模,其中n是无符号整数类型的位宽度。简单来说,这些无符号整数操作在溢出时会丢弃高位,程序可以依赖于"循环回绕"。
你尝试进行测试,但得到了不一致的结果。根据你提供的链接(http://play.golang.org/p/sJxtSHbigT),代码如下:
package main
import "fmt"
func main() {
fmt.Println("test")
var num uint32 = 1 << 35
}
这会导致错误:
prog.go:7: constant 34359738368 overflows uint32
[process exited with non-zero status]
但根据规范,不应该出现错误,而是应该看到结果为0。
英文:
Go spec say on unsigned integer overflow:
> For unsigned integer values, the operations +, -, *, and << are
> computed modulo 2n, where n is the bit width of the unsigned integer's
> type. Loosely speaking, these unsigned integer operations discard high
> bits upon overflow, and programs may rely on ''wrap around''.
I try to test it, but get inconsistent result - http://play.golang.org/p/sJxtSHbigT:
package main
import "fmt"
func main() {
fmt.Println("test")
var num uint32 = 1 << 35
}
This give error:
prog.go:7: constant 34359738368 overflows uint32
[process exited with non-zero status]
But according to spec should be no error but rather I should seen 0.
答案1
得分: 9
你引用的规范特指“+、-、*和<<操作的结果”。你试图定义一个常量,而不是查看这些操作的结果。
你也不能使用这些超大的值作为这些操作的输入。编译器不会为你包装任何值;这只是这些操作的运行时行为。
package main
import "fmt"
func main() {
var num uint32 = 1 + 1 << 35
fmt.Printf("num = %v\n", num)
}
prog.go:6: constant 34359738369 overflows uint32
[process exited with non-zero status]
下面是一个有趣的例子。
var num uint32 = (1 << 31) + (1 << 31)
fmt.Printf("num = %v\n", num)
prog.go:6: constant 4294967296 overflows uint32
[process exited with non-zero status]
在这种情况下,编译器试图在编译时计算(1 << 31) + (1 << 31)
,得到常量值4294967296
,它太大而无法容纳。
var num uint32 = (1 << 31)
num += (1 << 31)
fmt.Printf("num = %v\n", num)
num = 0
在这种情况下,加法是在运行时执行的,值会像你预期的那样进行包装。
英文:
The specification you quote refers specifically to the results of "the operations +, -, *, and <<". You're trying to define a constant, not looking at the result of one of those operations.
You also can't use those over-sized values for the input of those operations. The compiler won't wrap any values for you; that's just the runtime behaviour of those operations.
package main
import "fmt"
func main() {
var num uint32 = 1 + 1 << 35
fmt.Printf("num = %v\n", num)
}
<!-- -->
prog.go:6: constant 34359738369 overflows uint32
[process exited with non-zero status]
Here's an interesting example.
var num uint32 = (1 << 31) + (1 << 31)
fmt.Printf("num = %v\n", num)
<!-- -->
prog.go:6: constant 4294967296 overflows uint32
[process exited with non-zero status]
In this case, the compiler attempts to evaluate (1 << 31) + (1 << 31)
at compile-time, producing the constant value 4294967296
, which is too large to fit.
var num uint32 = (1 << 31)
num += (1 << 31)
fmt.Printf("num = %v\n", num)
<!-- -->
num = 0
In this case, the addition is performed at run-time, and the value wraps around as you'd expect.
答案2
得分: 3
这是因为1 << 35
是一个无类型的常量表达式(它只涉及数值常量)。直到你赋值给它之前,它才成为uint32
类型。Go语言禁止你将一个常量表达式赋值给一个变量,如果这样做会导致溢出,因为这种情况几乎肯定是无意的。
英文:
That's because 1 << 35
is an untyped constant expression (it only involves numerical constants). It doesn't become an uint32
until you assign it. Go prohibits you to assign to a variable a constant expression that would overflow it as stuff like that is almost certainly unintentional.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论