c# byte类型数据移位 溢出 50
byte iTmp = 0x0A;
iTmp <<= 5; // 这样写可以!运算正确!
// iTmp = iTmp << 5; // 这样写不可以!为什么?
// iTmp = Convert.ToByte(iTmp << 5);// 这样写可以!运行报溢出!为什么? 展开
1)iTmp <<= 5
这个语句是正确的。因为执行这个语句仅需要运算一次,也就是说,对byte类型的iTemp变量直接执行一次左移5位的运算。运算过程中,变量类型明确为byte类型。
参考MSDN:https://msdn.microsoft.com/zh-cn/library/ayt2kcfb.aspx
2)iTmp = iTmp << 5
从语法上,这句话与1)具有相当的含义;但是运算处理上有微妙的差异:首先,iTmp << 5 得出的中间结果,这个中间结果的类型为int或uint;然后,再将中间结果赋值给iTmp。错误出现在第二步上:无法将int或uint类型的中间结果赋值给byte类型的iTmp。要防止错误,必须使用强制转换:
iTmp = (byte)(iTmp << 5 );
3)iTmp = Convert.ToByte(iTmp << 5) 发生错误的根本原因与2)相同,也就是计算iTmp << 5的中间结果的类型为int或uint。要防止错误,也必须使用强制转换:
iTmp = Convert.ToByte((byte)(iTmp << 5 ));
这样写也能得到正确结果,但是很啰嗦、很别扭!
4)总之,关键点在于:一定要注意运算中间结果的类型!!!
0x0A <<5 = 0x140 超出byte的最大值0xFF了
iTmp << 5; 的值类型是int无法隐式转换为byte类型
使用unchecked 来防止溢出报错
unchecked{
iTmp =(byte)(iTmp <<5);
}
在C语言里以下两个表达式不是等效的吗?
iTmp <<= 5;
iTmp = iTmp << 5;
还有iTmp是byte类型的只有8位,如果向左移位时超出部分应该被丢弃,不应该存在0x0A <<5 = 0x140这种说法吧?
自己去MSDN上看吧。C#和C里是不一样的。他把iTmp 隐式转换为int类型再进行位移操作的,位移本身不会溢出。但你把一个大于byte.Max的数转换为byte类型时会报溢出。
左移运算符 (<<) 将第一个操作数向左移动第二个操作数指定的位数。 第二个操作数的类型必须是一个 int 或具有向 int 的预定义隐式数值转换的类型。
备注
如果第一个操作数是 int 或 uint(32 位数),则移位数由第二个操作数的低 5 位给出。 也就是实际的 shift 计数为 0 到 31 位。
如果第一个操作数是 long 或 ulong(64 位数),则移位数由第二个操作数的低 6 位给出。 也就是实际的 shift 计数为 0 到 63 位。
不在移位后第一个操作数类型范围内的任意高序位均不会使用,低序空位用零填充。 移位操作从不导致溢出。
https://msdn.microsoft.com/zh-cn/vbrun/a1sway8w.aspx