C/C++移位操作

12 篇文章 0 订阅
本文详细解析了C/C++中的无符号数和有符号数移位操作。无符号数左移右移均补0,规则简单;有符号数左移遵循乘法规则,但符号位变化可能导致正负号改变,右移时正数补0,负数补1,导致结果可能与除法不同。建议在代码中使用无符号数进行位移操作以避免复杂性。
摘要由CSDN通过智能技术生成


1.无符号数移位

a.规定移动的位数必须是正整数,并且不得大于或者等于类型的位宽,否则行为不确定。
例如:
unsigned char移动的位数必须是[0,7]
unsigned short移动位数必须是[0,15]
unsigned long移动位数必须是[0,31]

b.无论左移还是右移,移出位数范围的丢掉,然后补0. 移动的位数可以是0,结果与原值相同。左移n位等价于乘以2的n次方。 右移n位等价于除以2的n次方。当左移丢掉最左边的1时,在正数表达上表示溢出,超出该类型表达的值的范围了。
以unsigned char作为例子:
0x59 – 01011001
0x59 << 0, 01011001 == 01011001,
0x59 << 1, 01011001 --> 1011001,0
0x59 << 2, 01011001 --> 011001,00
0x59 << 3, 01011001 --> 11001,000
0x59 << 4, 01011001 --> 1001,0000
0x59 << 5, 01011001 --> 001,00000
0x59 << 6, 01011001 --> 01,000000
0x59 << 7, 01011001 --> 1,0000000

0x59 >> 0, 01011001 == ,01011001
0x59 >> 1, 01011001 --> 0,0101100
0x59 >> 2, 01011001 --> 00,010110
0x59 >> 3, 01011001 --> 000,01011
0x59 >> 4, 01011001 --> 0000,0101
0x59 >> 5, 01011001 --> 00000,010
0x59 >> 6, 01011001 --> 000000,01
0x59 >> 7, 01011001 --> 0000000,0

c.我们一般用位运算的场景都是无符号的,规则也是足够简单清晰不容易出错。


2.有符号数移位

a.有符号数的左移操作与无符号数一样的补0,区别是由于最高位是符号位,当左移导致最高位的变化时,结果的正负号就会改变。
有符号数移位依然遵循“左移n位等价于乘以2的n次方”的规则,而左移导致的符号位的变化,意味着在算术上, 原来的值乘以2的n次方后,已经超出了该类型能表示的值的范围,也就是溢出。

b.有符号数右移操作,当有符号数为正数的情况下,左边补0, 当有符号数为负数的情况下,左边补1。
由于有符号数是用补码表示的,最大限度但不完全遵循“右移n位等价于除以2的n次方”的规则,为了保持右移相当于除以2的算术特性,首先符号位必定不能改变。恰好补码的表示方式在右移的情况下,正数补0完全对应除以2的n次方, 负偶数往前面补1在算术上也完全对应除以2的n次方, 但是!负奇数在右移前面补1的情况,并不等同于除以2的n次方
那是因为在C/C++语言里规定除法是趋0截断取整。 而右移操作则是向小的值取整。

例如:
10 / 2 = 5; // 整除
11 / 2 = 5; // 不能整除,截断后的值,向0靠近,比实际要小。
-10 / 2 = -5; // 整除
-11 / 2 = -5; // 不能整除,截断后的值,向0靠近,比实际要大。


00001010 = 10
00001011 = 11
10 >> 1 = 5; 0,0000101 // 与除以2结果一致
11 >> 1 = 5; 0,0000101 // 与除以2结果一致

11110110 = -10
11110101 = -11
-10 >> 1 = -5; 1,1111011 // 与除以2结果一致
-11 >> 1 = -6; 1,1111010 // 与除以2结果不一致

(-11 / 2) 与 (-11 >> 1)并不相等。-11 / 2实际上是-5.5。 除法规定向0取整, 最终值是-5。而右移1位则是向小的值取整, 因此变成-6了。


总结

1.无符号数左移右移规则简单,空位补0。
2.有符号数:
a.正数不能整除2时, 向小取整实际上就是趋0取整, 因此除以2或者右移1位的结果是一样的。
b.负数不能整除2时,向小取整与趋0取整的方向刚好相反, 因此除以2或者右移1位的结果不一样。
c.整除时,不存在取整问题,无论正数负数除以2与右移1位的结果是一样的。
3.建议代码中所有位移操作都必须用无符号数,确保逻辑清晰简单。 而乘以2除以2操作不能用移位来代替, 大部分场景,现代的编译器的优化功能已不需要我们专门用移位来代替乘除法。

负数右移的例子如下:
0x89 – 10001001 – -119
0x89 >> 0, 10001001 == ,10001001 -119
0x89 >> 1, 10001001 --> 1,1000100 -60 并非等于-119 / 2。
0x89 >> 2, 10001001 --> 11,100010 -30 等于 -60 / 2
0x89 >> 3, 10001001 --> 111,10001 -15 等于 -30 / 2
0x89 >> 4, 10001001 --> 1111,1000 -8 并非等于-15 / 2。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值