packagemainimport("fmt")const(cimaxuint8=255)funcmain(){variuint8varimaxuint8=255i=imax
2 回答
阿波罗的战车
TA贡献1862条经验 获得超6个赞
以下是一些不够严谨的分析。参照文档进行研究,Go必然有这么几个特点:编译型语言,编译器的静态求值是自然的。必须使用强制类型转换。甚至于对一个uint16变量赋uint8的值都是不允许的。整数字面值不包含存储空间的大小,可以直接赋给各种uintX(必须不溢出)。<<运算的结果的类型,以左侧操作数为准。而从表象上来看:静态求值的规则是先不顾代码范围,强制求值,之后再塞回目标的存储空间中对变量左移的时候,会直接考虑存储空间大小,将左移的数据丢弃对于第1条,如下的代码都会出现同样的错误。对于这两个例子,因为<<左侧都是uint8,所以最终的结果也是uint8,则得出的结果装不下uint8就会报错,哪怕最后准备了uint16的容器也不行:constc_i8uint8=255vari16uint16i16=uint16(c_i8<<4)//constant4080overflowsuint8i16=uint16(uint8(255)<<4)//constant4080overflowsuint8对于第2条,如下的代码都可以正确执行:vari8uint8vari8_2uint8=255i8=i8_2<<4fmt.Printf("%x\n",i8)//f0i8_2<<=4fmt.Printf("%x\n",i8_2)//f0所以并不是说常量不能作为操作数,而是常量左移之后,Go面对溢出的行为并不是截断而是报错。临时对付这个问题,你可能需要先用不定长度的uint类型绕开溢出的限制,再用掩码(&0xFF)运算去约束结果的范围:constc_i8uint8=255vari16uint16i16=uint16(uint(c_i8)<<4&0xFF)fmt.Printf("%x\n",i16)更深入的分析期待其他回答者的补充。
一只斗牛犬
TA贡献1784条经验 获得超2个赞
>>>gobuilda.go#command-line-arguments./a.go:18:constant4080overflowsuint8这错误很明显了啊,溢出了。你那个变量的类型是uint8,能存储的最大值是255。为什么「变量」没有报溢出的错误呢?因为它是「变量」,编译器在编译时没能确定执行到那里的时候它一定会溢出(说不定你在什么地方改变了它的值所以不会溢出了)。编译器会保证「常量」不会变化(你不能以正常的方式对它赋值),所以编译的时候它能够把这些地方先计算了,于是它发现你在给一个uint8类型的变量赋值一个超过它的最大值的数。(大概是因为go太新了吧。像这种C程序,gcc带优化编译完之后只会剩下输出语句,计算都会提前算了。不过对于变量也不会有警告。)
添加回答
举报
0/150
提交
取消