关于将uint8转换为int8的困惑

关于将uint8转换为int8的困惑

问题描述:

I want to convert uint8 to int, so I write a const 0xfc, and try to use int8(0xfc) to convert it. However the code raises an error:

package main

import (
    "fmt"
)

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

But if I defer the type conversion after assignment, the code can work around.

package main

import (
    "fmt"
)

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

My question:

  • Is there any difference between these two codes?
  • Why does the first one raise a compile error?

我想将 uint8 code>转换为 int code>,所以我 编写一个const 0xfc code>,然后尝试使用 int8(0xfc) code>进行转换。 但是,代码会引发错误: p>

 包main 
 
import(
“ fmt” 
)
 
func  main(){
a:= int8(0xfc)//编译错误:常量252溢出int8 
b:= a 
 fmt.Println(b)
} 
  code>  pre> 
 \  n 

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

 包main 
 
import  (
“ fmt” 
)
 
func main(){
a:= 0xfc 
b:= int8(a)//好的
 fmt.Println(b)
} 
  code>   pre> 
 
 

我的问题: p>

  • 这两个代码之间有什么区别? li>
  • 为什么 第一个引发编译错误? li> ul> div>

  1. see: https://golang.org/ref/spec#Constant_expressions

The values of typed constants must always be accurately representable by values of the constant type. The following constant expressions are illegal:

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. see: https://blog.golang.org/constants

not all integer values can fit in all integer types. There are two problems that might arise: the value might be too large, or it might be a negative value being assigned to an unsigned integer type. For instance, int8 has range -128 through 127, so constants outside of that range can never be assigned to a variable of type int8:
var i8 int8 = 128 // Error: too large.
Similarly, uint8, also known as byte, has range 0 through 255, so a large or negative constant cannot be assigned to a uint8:
var u8 uint8 = -1 // Error: negative value.
This type-checking can catch mistakes like this one:

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

If the compiler complains about your use of a constant, it's likely a real bug like this.


My actual demand is to convert a byte to int32 when parsing a binary file. I may encounter the constant byte 0xfc, and should transfer it to the int8 before converting it to the int32 with the consideration of sign.

Yes, this is the way to go:


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

Is there any difference between these two codes?

The first example uses a constant expression. The second uses plain expressions. Constant expressions are evaluated at compile time with different rules from plain expressions.

Why does the first one raise a compile error?

The int8(0xfc) is a typed constant expression. Values of typed constants must always be accurately representable by values of the constant type. The compiler reports an error because the value 252 cannot be represented by the values of int8.

Based on comments on other answers, I see that the goal is to get an int32 from a byte with sign extension. Given a byte variable b, use the expression int32(int8(b)) to get the int32 value with sign extension.