Gloang移位运算符转换

Sal*_*d83 3 type-conversion go operator-keyword

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

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

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

“移位表达式中的右操作数必须具有无符号整数类型,或者是可由uint类型的值表示的无类型常量。 如果非恒定移位表达式的左操作数是无类型常量,则首先将其隐式转换为该类型它会假设是否仅将shift表达式替换为其左操作数。”

来自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
Run Code Online (Sandbox Code Playgroud)

更新:

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

package main

import (
    "fmt"
)

func main() {
v := int16(4336)
    fmt.Println(int8(v))
}
Run Code Online (Sandbox Code Playgroud)

该程序返回 -16

如何数量4336成为-16在转换int16int8

icz*_*cza 5

如果您有这个:

var s uint = 33
fmt.Println(1 << s)
Run Code Online (Sandbox Code Playgroud)

然后引用的部分适用:

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

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

fmt.Println(1)
Run Code Online (Sandbox Code Playgroud)

在上面,未类型的常量1将转换为int,因为这是其默认类型。常量的默认类型在Spec中:常量:

非类型化常数具有一个默认类型,其是其中恒定隐式转换在需要类型化值,例如上下文,在该类型短变量声明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)
Run Code Online (Sandbox Code Playgroud)

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

int size: 4
0
0
8589934592
Run Code Online (Sandbox Code Playgroud)

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

int size: 8
8589934592
0
8589934592
Run Code Online (Sandbox Code Playgroud)

另请参见The Go Blog:Constants,了解常量在Go中的工作方式。

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

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

请参阅Go如何对常量执行算术运算?

更新:

回答您的添加问题:从转换int16int8只需保留最低的8位。整数使用2的补码格式表示,1如果数字为负数,则最高位为整数。

规格:转化次数中对此进行了详细说明

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

因此,当您将int16值转换为时int8,如果源编号1在第7位(第8位)处于第7位,则即使源不是负数,结果也将是负数。同样,如果源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()
}
Run Code Online (Sandbox Code Playgroud)

输出(在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
Run Code Online (Sandbox Code Playgroud)

查看相关问题:

将int64强制转换为uint64时,是否保留符号?

格式打印64位整数-1(十六进制在golang和C之间出现偏差)