C/C++右移高位补0还是1?
[TOC]
场景列举
问题
先抛出代码,如下输出的结果应该是什么?
int main()
{
int16_t val1 = 0xF000;
int16_t val2 = 0x7700;
int16_t val3 = val1 >> 8 | val2;
printf("val3 = %x", val3);
return 0;
}
输出
执行输出,正确结果如下,是否符合你的预期呢?
val3 = fffffff0
分析
有经验的程序员一眼可能就会发现问题,并给出正确的答案。当然一定会存在给出0x77F0
的答案,例如初次“踩坑”的作者寄几。
为此特意回顾基础,请教了一下AI
有关右移的规则:
Me: 魔镜啊魔镜,请告诉我C/C++ 教科书中右移时,空位补值规则
魔镜:哎呀,聪明的人类终于踩到坑了吧。让我来告诉你正确的规则,小笔记记起来,好吗!
1. 无符号类型,高位补0。
2. 有符号类型:
若被移位数为正,高位补0。
若被移位数为负,高位补1(算术右移)。
Me: 魔镜,你的话过多了,我有点生气。另外,告诉我左移补值规则!
魔镜: 好的,收回刚才的话,请不要放在心上。如下是左移规则:
所有类型(无符号和有符号), 右边空出的位置总是补0。
通过与AI
的友好沟通,发现了其中的问题。右移并非总是补0,而是依据变量类型和正负值来决定的。
规避措施
既然发现问题所在,就要在日常开发过程中规避,常见方式如下:
- 总是使用无符号类型
规则说明,无符号类型右移高位总是补0。 - 使用掩码校正
在右移后,通过掩码限定右移后的有效位范围,确保结果符合预期。uint16_t mask = 0xFF; uint16_t shiftedVal = (val >> 8) & mask; // 确保只保留低8位
Bug修复
按照规避措施,修改问题代码:
- 总是使用无符号类型
修改
int main()
{
uint16_t val1 = 0xF000;
uint16_t val2 = 0x7700;
uint16_t val3 = val1 >> 8 | val2;
printf("val3 = %x", val3);
return 0;
}
输出
val3 = 77f0
- 使用掩码校正
修改
int main()
{
int16_t val1 = 0xF000;
int16_t val2 = 0x7700;
int16_t val3 = (val1 >> 8 & 0xFF) | val2;
printf("val3 = %x", val3);
return 0;
}
输出
val3 = 77f0
总结
右移经常在日常开发用到,如果碰到有这种代码存在导致bug,排查起来也比较费劲。像这种类似的应该还有很多,只有撞上了才记忆深刻。