Gloang移位运算符转换

时间:2019-03-05 08:39:28

标签: go type-conversion operator-keyword

我无法在golang中理解1<<s如果0如何返回var s uint = 33。 但是1<<33返回8589934592。 移位运算符转换如何以0值结束。

我正在阅读语言规范,并停留在本节中: https://golang.org/ref/spec#Operators

特别是来自文档的这一段:

  

“移位表达式中的右操作数必须具有无符号整数   type或可以由uint类型的值表示的无类型常量。   如果非恒定移位表达式的左操作数是未键入的   常量,首先将其隐式转换为假定的类型   如果仅将移位表达式替换为其左操作数。”

Golang官方文档中的一些示例:

var s uint = 33
var i = 1<<s                  // 1 has type int
var j int32 = 1<<s            // 1 has type int32; j == 0
var k = uint64(1<<s)          // 1 has type uint64; k == 1<<33

更新

另一个非常相关的问题,例如:

package main

import (
    "fmt"
)

func main() {
v := int16(4336)
    fmt.Println(int8(v))
}

该程序返回-16

在将4336转换为-16时,数字int16变成int8

2 个答案:

答案 0 :(得分:5)

如果您有这个:

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

然后引用的部分适用:

  

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

由于s不是常量(它是一个变量),因此1 >> s是一个非恒定移位表达式。左操作数是1,它是一个无类型的常量(例如int(1)将是一个类型常量),因此它将转换为一个类型,如果表达式只是{{1} }代替1

1 << s

在上面,未类型的常量fmt.Println(1) 将转换为1,因为这是其默认类型。常量的默认类型为Spec: Constants:

  

未类型化的常量具有默认类型,该类型是在需要输入值的上下文中(例如,在short variable declaration中,例如{ {1}},其中没有显式类型。无类型常量的默认类型分别是inti := 0boolruneintfloat64,具体取决于它是布尔,符文,整数,浮点数,复数或字符串常量。

以上结果取决于体系结构。如果complex128为32位,则为string。如果int是64位,它将是0(因为将int位移位33次将使其移出32位8589934592数字)。

在Go游乐场中,1的大小为32位(4字节)。参见以下示例:

int

以上输出(在Go Playground上尝试):

int

如果我在64位计算机上运行上述应用,则输出为:

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中常量的工作方式,请参见The Go Blog: Constants

请注意,如果您写int size: 4 0 0 8589934592 ,则不一样,那不是一个非恒定移位表达式,您的引用适用于:“非恒定移位表达式的左操作数“ int size: 8 8589934592 0 8589934592 是一个常数移位表达式,在“恒定空间”中求值,结果将转换为1 << 33,该值不适合32位1<<33,因此可以进行编译时间错误。它适用于变量,因为变量可能会溢出。常量不会溢出:

  

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

请参见How does Go perform arithmetic on constants?

更新

解决您的添加问题:从int转换为int只会保留最低的8位。整数使用2's complement格式表示,如果数字为负,则最高位为int16

这在Spec: Conversions:

中有详细说明
  

在整数类型之间进行转换时,如果值是有符号整数,则将其符号扩展为隐式无限精度;否则为零扩展。 然后将其截断以适合结果类型的大小。例如,如果为int8,则为1。转换总是产生一个有效值。没有溢出迹象。

因此,当您将v := uint16(0x10F0)的值转换为uint32(int8(v)) == 0xFFFFFFF0时,如果源编号在第7位(第8位)的位置上有一个int16,则结果将为负,即使源不是负面的。同样,如果源在位置7处有int8,则即使源为负,结果也将为正。

请参见以下示例:

1

输出(在Go Playground上尝试):

0

查看相关问题:

When casting an int64 to uint64, is the sign retained?

Format printing the 64bit integer -1 as hexadecimal deviates between golang and C

答案 1 :(得分:2)

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