为了账号安全,请及时绑定邮箱和手机立即绑定

Golang 移位运算符转换

Golang 移位运算符转换

Go
qq_笑_17 2023-06-12 15:53:41
我不明白在 golang 中如何1<<s返回0if var s uint = 33。而是1<<33回归8589934592。移位运算符转换如何以 0 值结束。我正在阅读语言规范并停留在本节中: https ://golang.org/ref/spec#Operators特别是文档中的这一段:“移位表达式中的右操作数必须具有无符号整数类型,或者是由 uint 类型的值表示的无类型常量。 如果非常量移位表达式的左操作数是无类型常量,则首先将其隐式转换为类型它会假设移位表达式是否被单独的左操作数替换。”官方 Golang 文档中的一些示例:var s uint = 33var i = 1<<s                  // 1 has type intvar j int32 = 1<<s            // 1 has type int32; j == 0var k = uint64(1<<s)          // 1 has type uint64; k == 1<<33更新:另一个非常相关的问题,举个例子:package mainimport (    "fmt")func main() {v := int16(4336)    fmt.Println(int8(v))}本节目回归-16数字如何4336转换-16为int16int8
查看完整描述

2 回答

?
慕莱坞森

TA贡献1810条经验 获得超4个赞

如果你有这个:

var s uint = 33
fmt.Println(1 << s)

然后引用的部分适用:

如果非常量移位表达式的左操作数是无类型常量,则首先将其隐式转换为移位表达式单独由其左操作数替换时所假定的类型。

因为s不是常量(它是变量),所以1 >> s是非常量移位表达式。左操作数是1一个无类型常量(例如int(1),将是一个类型化常量),因此它被转换为一个类型,如果表达式简单地1代替1 << s:

fmt.Println(1)

在上面,无类型常量1将被转换为int,因为这是它的默认类型。常量的默认类型在Spec: Constants:

无类型常量有一个默认类型,即常量在需要类型化值的上下文中隐式转换为的类型,例如,在没有显式类型的短变量声明中。i := 0无类型常量的默认类型分别为boolruneintfloat64complex128string具体取决于它是布尔值、符文、整数、浮点数、复数还是字符串常量。

上述结果取决于体系结构。如果int是 32 位,它将是0. 如果int是 64 位,它将是8589934592(因为将位移动133 次会将其移出 32 位int数字)。

在 Go 操场上,大小int为 32 位(4 字节)。看这个例子:

fmt.Println("int size:", unsafe.Sizeof(int(0)))


var s uint = 33


fmt.Println(1 << s)

fmt.Println(int32(1) << s)

fmt.Println(int64(1) << s)

上面的输出(在Go Playground上试试):


int size: 4

0

0

8589934592

如果我在我的 64 位计算机上运行上面的应用程序,输出是:


int size: 8

8589934592

0

8589934592

请注意,如果您编写1 << 33,那是不一样的,那不是一个非常量移位表达式,您的引用适用于:"the left operand of a non-constant shift expression"1<<33是一个常量移位表达式,在“常量空间”进行计算,结果将转换为int不适合 32 位的int,因此会出现编译时错误。它适用于变量,因为变量可能会溢出。常量不会溢出:

数值常量表示任意精度的精确值并且不会溢出。

从 转换为int16int8保留最低 8 位。整数使用2 的补码格式表示,其中最高位是1负数。

这在规范中有详细说明:转换:

在整数类型之间转换时,如果值为有符号整数,则将其符号扩展为隐式无限精度;否则为零扩展。然后将其截断以适合结果类型的大小。例如,如果v := uint16(0x10F0),则uint32(int8(v)) == 0xFFFFFFF0。转换总是产生有效值;没有溢出的迹象。

因此,当您将int16值转换为 时int8,如果源编号的1位位置为 7(第 8 位),则结果将为负,即使源不是负数。类似地,如果源在位0位置 7,结果将为正,即使源为负。

看这个例子:

for _, v := range []int16{4336, -129, 8079} {

    fmt.Printf("Source    : %v\n", v)

    fmt.Printf("Source hex: %4x\n", uint16(v))

    fmt.Printf("Result hex: %4x\n", uint8(int8(v)))

    fmt.Printf("Result    : %4v\n", uint8(int8(v)))

    fmt.Println()

}

输出(在Go Playground上尝试):


Source    : 4336

Source hex: 10f0

Result hex:   f0

Result    :  -16


Source    : -129

Source hex: ff7f

Result hex:   7f

Result    :  127


Source    : 8079

Source hex: 1f8f

Result hex:   8f

Result    : -113


查看完整回答
反对 回复 2023-06-12
?
皈依舞

TA贡献1851条经验 获得超3个赞

您正在以 32 位模式构建和运行程序(去游乐场?)。其中,int 是 32 位宽的,其行为与 int32 相同。



查看完整回答
反对 回复 2023-06-12
  • 2 回答
  • 0 关注
  • 116 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信