为什么golang中的64位溢出没有留下位移?

为什么golang中的64位溢出没有留下位移?,第1张

概述我看了 A Tour of Go,我对他们的基本类型中的东西感到困惑.示例: MaxInt uint64 = 1<<64 - 1 不应该在无符号的64位整数中向左移动1 64个位置导致溢出(a.k.a.稍微移过MSB)? 但是,在将行更改为以下内容之前,编译器不会抱怨: MaxInt uint64 = 1<<65 - 1./basic-types.go:5: constant 我看了 A Tour of Go,我对他们的基本类型中的东西感到困惑.示例:
MaxInt uint64     = 1<<64 - 1

不应该在无符号的64位整数中向左移动1 64个位置导致溢出(a.k.a.稍微移过MSB)?

但是,在将行更改为以下内容之前,编译器不会抱怨:

MaxInt uint64     = 1<<65 - 1./basic-types.go:5: constant 36893488147419103231 overflows uint64

如果我编写一些代码来迭代不同长度的左移,包括按照上面的例子中的65移动导致编译器barf,我看到两件事:

>它的行为与我预期的一样,因为1<<<<<<<<<<<<<<<
>它不再溢出(嗯?!?!)

码:

package mainimport "fmt"func main() {    for i := 60; i < 66; i++ {        var j uint64 = 1 << uint64(i) - 1        fmt.Printf("%2d | %64b | %#18x\n",i,j,j)    }

输出:

60 |     111111111111111111111111111111111111111111111111111111111111 |  0xfffffffffffffff61 |    1111111111111111111111111111111111111111111111111111111111111 | 0x1fffffffffffffff62 |   11111111111111111111111111111111111111111111111111111111111111 | 0x3fffffffffffffff63 |  111111111111111111111111111111111111111111111111111111111111111 | 0x7fffffffffffffff64 | 1111111111111111111111111111111111111111111111111111111111111111 | 0xffffffffffffffff65 | 1111111111111111111111111111111111111111111111111111111111111111 | 0xffffffffffffffff
当你写作
1<<64

上面的1不是int64.这是一个不变的文字.从语言规范:

Constant Expressions are always evaluated exactly; intermediate values
and the constants themselves may require precision significantly
larger than supported by any predeclared type in the language.

因此,常量文字在编译时进行评估,并且可能非常大,因为它不是特定类型的语言实现.

实际上下面会出现溢出错误:

var i int64i = 1<<65 - 1

因为现在常量文字表达式的计算结果大于int64可以包含的值.

阅读有关此here的更多信息.

要了解为什么您的示例代码适用于i = 65,请参阅Golang specs中的以下规范:

The right operand in a shift Expression must have unsigned integer
type or be an untyped constant that can be converted to unsigned
integer type. If the left operand of a non-constant shift Expression
is an untyped constant,it is first converted to the type it would
assume if the shift Expression were replaced by its left operand
alone.

上面的blod部分涉及您的代码.请考虑以下代码:

a := 66var j uint64 = 1<<uint64(a) - 1

在移位运算符中,右 *** 作数是一个非常数的exrpession.因此整个换档 *** 作变为非恒定的换档表达式.因此,如上所述,左 *** 作数1被转换为uint64.

现在,正在对uint64(1)进行转换,可以使用<<到你想要的地方.您可以将其移到64位以上,实现将很容易实现.但在这种情况下,持有上面的uint64(1)的内存将包含全零. 请注意,根据语言规范,此行为与溢出不同.同样,只要右运算符不是常量表达式,语言实现就允许尽可能多的移位.例如,这将起作用:

a := 6666var j uint64 = 1<<uint64(a) - 1 // non-constant shift Expression

这样想吧.早些时候,1是无类型的.它具有任意精度(取决于实现)并且返回整数(所有位).现在,因为它是uint64,所以只考虑前64位.

这仍然会导致溢出,因为左 *** 作数1是无类型并且可以包含大量位,为uint64返回的值太大:

var j uint64 = 1<<uint64(66) - 1 // overflow. Note that uint64(64)fmt.Println(j)                   // is typed,but it's still a constant
总结

以上是内存溢出为你收集整理的为什么golang中的64位溢出没有留下位移?全部内容,希望文章能够帮你解决为什么golang中的64位溢出没有留下位移?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1293770.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-10
下一篇 2022-06-10

发表评论

登录后才能评论

评论列表(0条)

保存