Go语言中用位移位拼接uint8为uint16的代码异常排查
问题分析与解决
这个问题的核心是Go语言中整数类型的溢出行为和类型转换时机和C语言存在差异,导致你的位操作结果不符合预期。
问题根源拆解
先看你的Go代码:
func DereferenceWord(addr uint32) uint16 { return uint16(memoryPointer[addr]) | uint16(memoryPointer[addr + 1] << 8) }
这里的memoryPointer[addr + 1]是uint8类型(8位无符号整数),当你执行<< 8操作时:
- uint8的取值范围是0~255,二进制仅占8位,左移8位后所有有效位都会被移出,结果直接变成0
- 之后再把这个0转成uint16,数值依然是0
- 最后和
uint16(memoryPointer[addr])(也就是0xff)做按位或,结果自然是0xff
而你的C代码:
uint16_t connect(uint8_t a, uint8_t b) { return (uint16_t) a | (uint16_t) b << 8; }
这里是先把b转成uint16(16位)再左移8位,左移后b的二进制是0xff00,再和a的0x00ff按位或,得到正确的0xffff。
修正后的Go代码
只需要调整类型转换的时机,先把uint8转成uint16再做左移操作:
func DereferenceWord(addr uint32) uint16 { return uint16(memoryPointer[addr]) | (uint16(memoryPointer[addr+1]) << 8) }
或者为了可读性更清晰,可以拆分步骤:
func DereferenceWord(addr uint32) uint16 { lowByte := uint16(memoryPointer[addr]) highByte := uint16(memoryPointer[addr+1]) << 8 return highByte | lowByte }
这样当两个字节都是0xff时,highByte会是0xff00,和lowByte的0x00ff按位或后,就能得到正确的0xffff。
额外验证
对比你的SetWord函数,它是先把uint16的data拆分高低位存到内存里,逻辑完全正确:先右移0位取低8位,再右移8位取高8位。修正后的DereferenceWord刚好是这个过程的逆操作,完全匹配内存存储规则。
内容的提问来源于stack exchange,提问作者Safal Aryal
相关产品推荐
相关产品推荐

