提示:以下是本篇文章正文内容
文中第四部分代码例子来自于此篇博客,衷心感谢此博主的分享《https://blog.csdn.net/weixin_42167759/article/details/85624722》
自己加了不少内容上去,更好去理解。
Windows下进行socket网络编程,编写校验和时遇到的问题,记录如下。
位移位运算符是将数据看成二进制数,对其进行向左或向右移动若干位的运算。
位移位运算符分为左移和右移两种,均为双目运算符。
例如: 8>>3 (意思是8向右移动3位)第一运算对象是移位对象,第二个运算对象是所移的二进制位数。
逻辑移位
简单理解就是物理上按位进行的左右移动,两头用0进行补充,不关心数值的符号问题。
逻辑左移/右移指令只有它们的移位方向不同,移位后空出的位都补0。
算术移位
同样也是物理上按位进行的左右移动,两头用0或1进行补充,但必须确保符号位不改变。
算术左移SAL把目的操作数的低位向高位移,空出的低位补0;
算术右移SAR把目的操作数的高位向低位移,空出的高位用最高位(符号位,0或1)填补 。
但我们好奇的是“i<<3”和“i>>3”到底采用的是算术还是逻辑移位呢?
当向左边移动3位,采用的什么方式的移动???
#include
int main()
{
unsigned int ui = 8;
ui = ui << 3;
printf("ui = %d 无符号类型左移(正数)\n", ui);
int i = 8;
i = i << 3;
printf("i = %d 有符号类型左移(正数)\n", i);
int fi = -8;
fi = fi << 3;
printf("fi = %d 有符号类型左移(负数)\n", fi);
return 0;
}
结果显示:
ui = 64 无符号类型左移(正数)
i = 64 有符号类型左移(正数)
fi = -64 有符号类型左移(负数)
分析:
注意数在计算机里的存储和表示都是补码!!!
无符号
8 00000000 00000000 00000000 00001000
<----- 左移3位,低位补0
64 00000000 00000000 00000000 01000000
有符号(即最高位为符号位)
8 00000000 00000000 00000000 00001000
<----- 左移3位,低位补0
64 00000000 00000000 00000000 01000000
有符号(即最高位为符号位)
-8 11111111 11111111 11111111 11111000
<----- 左移3位,低位补0
-64 11111111 11111111 11111111 11000000
结论:左移时总是移位和补零,无论是有符号还是无符号
都可看作进行了逻辑左移
。
当向右边移动3位,采用的什么方式的移动???
#include
int main()
{
unsigned int ui = 8;
ui = ui >> 3;
printf("ui = %d 无符号类型右移(正数)\n", ui);
int i = 8;
i = i >> 3;
printf("i = %d 有符号类型右移(正数)\n", i);
int fi = -8;
fi = fi >> 3;
printf("fi = %d 有符号类型右移(负数)\n", fi);
return 0;
}
结果显示:
ui = 1 无符号类型左移(正数)
i = 1 有符号类型左移(正数)
fi = -1 有符号类型左移(负数)
分析:
注意数在计算机里的存储和表示都是补码!!!
无符号
8 00000000 00000000 00000000 00001000
-----> 右移3位,高位补0
1 00000000 00000000 00000000 00000001
有符号(即最高位为符号位)
8 00000000 00000000 00000000 00001000
-----> 右移3位,高位补符号位,即0
1 00000000 00000000 00000000 00000001
有符号(即最高位为符号位)
-8 11111111 11111111 11111111 11111000
-----> 右移3位,高位补符号位,即1
-1 11111111 11111111 11111111 11111111
结论:
右移时无符号数
是移位和补零,此时称为逻辑右移
;
右移时而有符号数
大多数情况下是移位和补最左边的位(也就是补最高有效位),移几位就补几位,此时称为算术右移
。
其实可以理解为左移扩大,右移缩小。
例如如下c代码:
int a = 8;
int b1 = a * 4
int b2 = a << 2 //左移2位相当于扩大4倍
int b3 = a / 4
int b4 = a >> 2 //右移2位相当于缩小4倍
结果
b1 = b2 = 4
b3 = b4=1
但是有时候想把两个8位二进制数拼成一个16位二进制,“左移<<” 与 "右移>>"就很重要。例如 00001000 与 00000011 拼接成00001000 00000011:
分析:
二进制
a 00001000
<--左移8位,低位补0
a 00001000 00000000
+
b 00000011
——————————————————————————
得到目标结果 00001000 00000011
在scoket网络编程,例如计算校验和时,都知道是以16位二进制进行相加,那么计算机是以8位二进制读取,如何将两个8位数字拼成一个16位数字,就是利用上方原理讲解。
具体可见之前写的笔记 《校验和之概念、计算原理、检验原理、实例计算、代码编程,力荐力荐力荐》
左移时总是移位和补零,无论是有符号还是无符号
都可看作进行了逻辑左移
。
右移时无符号数
是移位和补零,此时称为逻辑右移
;
右移时而有符号数
大多数情况下是移位和补最左边的位(也就是补最高有效位),移几位就补几位,此时称为算术右移
。
码字不易,谢谢点赞!!!
码字不易,谢谢点赞!!!
码字不易,谢谢点赞!!!