关于将uint8转换为int8的困惑

时间:2019-04-17 04:19:53

标签: go

我想将uint8转换为int,所以我写了一个常量0xfc,并尝试使用int8(0xfc)进行转换。但是代码会引发错误:

package main

import (
    "fmt"
)

func main() {
    a := int8(0xfc)  // compile error: constant 252 overflows int8
    b := a
    fmt.Println(b)
}

但是如果我在分配后推迟类型转换,则代码可以解决。

package main

import (
    "fmt"
)

func main() {
    a := 0xfc
    b := int8(a)  // ok
    fmt.Println(b)
}

我的问题:

  • 这两个代码之间有什么区别吗?
  • 为什么第一个会引发编译错误?

2 个答案:

答案 0 :(得分:5)

  1. 请参阅:https://golang.org/ref/spec#Constant_expressions
  

类型常量的值必须始终可以由常量类型的值准确表示。以下常量表达式是非法的:

uint(-1)     // -1 cannot be represented as a uint
int(3.14)    // 3.14 cannot be represented as an int
int64(Huge)  // 1267650600228229401496703205376 cannot be represented as an int64
Four * 300   // operand 300 cannot be represented as an int8 (type of Four)
Four * 100   // product 400 cannot be represented as an int8 (type of Four)
  1. 请参阅: https://blog.golang.org/constants
  

并非所有整数值都可以适合所有整数类型。可能会出现两个问题:该值可能太大,或者可能是分配给无符号整数类型的负值。例如,int8的范围是-128到127,因此永远不能将超出该范围的常量分配给int8类型的变量:
  var i8 int8 = 128 // Error: too large.
  类似地,uint8(也称为字节)的范围为0到255,因此不能为uint8分配较大或负的常量:
      var u8 uint8 = -1 // Error: negative value.
  这种类型检查可以发现这样的错误:

    type Char byte
    var c Char = '世' // Error: '世' has value 0x4e16, too large. 
     

如果编译器抱怨您对常量的使用,那么这很可能是真正的错误。


  

我的实际需求是在解析二进制文件时将byte转换为int32。我可能会遇到常量字节0xfc,应该在考虑符号的情况下将其转换为int8,然后再转换为int32

是的,这是要走的路:


    var b byte = 0xff
    i32 := int32(int8(b))
    fmt.Println(i32) // -1

答案 1 :(得分:2)

  

这两个代码之间有什么区别吗?

第一个示例使用constant expression。第二个使用普通表达式。常量表达式在编译时使用与普通表达式不同的规则求值。

  

为什么第一个会引发编译错误?

int8(0xfc)是键入的constant expression。类型常量的值必须始终可以由常量类型的值准确表示。编译器报告错误,因为值252无法用int8的值表示。

基于对其他答案的评论,我看到目标是从带有符号扩展名的字节中获取int32。给定字节变量b,请使用表达式int32(int8(b))来获得int32值,并带有符号扩展名。