从代码角度理解:C语言中的 “左移<<“ 与 “右移>>“,且结合应用场景

阅读前请看一下:我是一个热衷于记录的人,每次写博客会反复研读,尽量不断提升博客质量。文章设置为仅粉丝可见,是因为写博客确实花了不少精力。希望互相进步谢谢!!


提示:以下是本篇文章正文内容

文中第四部分代码例子来自于此篇博客,衷心感谢此博主的分享《https://blog.csdn.net/weixin_42167759/article/details/85624722
自己加了不少内容上去,更好去理解。

1、背景介绍

Windows下进行socket网络编程,编写校验和时遇到的问题,记录如下。


2、双目运算符

位移位运算符是将数据看成二进制数,对其进行向左或向右移动若干位的运算。

位移位运算符分为左移和右移两种,均为双目运算符。

例如: 8>>3 (意思是8向右移动3位)第一运算对象是移位对象,第二个运算对象是所移的二进制位数。

3、逻辑移位与算术移位

逻辑移位

简单理解就是物理上按位进行的左右移动,两头用0进行补充,不关心数值的符号问题。
	
逻辑左移/右移指令只有它们的移位方向不同,移位后空出的位都补0

算术移位

同样也是物理上按位进行的左右移动,两头用01进行补充,但必须确保符号位不改变。
	
算术左移SAL把目的操作数的低位向高位移,空出的低位补0;
	
算术右移SAR把目的操作数的高位向低位移,空出的高位用最高位(符号位,01)填补 。

但我们好奇的是“i<<3”和“i>>3”到底采用的是算术还是逻辑移位呢?


4、实例分析

4.1、左移

当向左边移动3位,采用的什么方式的移动???

#include <stdio.h>
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 

结论:左移时总是移位和补零,无论是有符号还是无符号都可看作进行了逻辑左移

4.2、右移

当向右边移动3位,采用的什么方式的移动???

#include <stdio.h>
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 

结论:
右移时无符号数是移位和补零,此时称为逻辑右移;
右移时而有符号数大多数情况下是移位和补最左边的位(也就是补最高有效位),移几位就补几位,此时称为算术右移

5、常用场景

其实可以理解为左移扩大,右移缩小。

例如如下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位数字,就是利用上方原理讲解。

具体可见之前写的笔记 《校验和之概念、计算原理、检验原理、实例计算、代码编程,力荐力荐力荐

6、总结

左移时总是移位和补零,无论是有符号还是无符号都可看作进行了逻辑左移

右移时无符号数是移位和补零,此时称为逻辑右移;

右移时而有符号数大多数情况下是移位和补最左边的位(也就是补最高有效位),移几位就补几位,此时称为算术右移


码字不易,谢谢点赞!!!
码字不易,谢谢点赞!!!
码字不易,谢谢点赞!!!

猜你喜欢

转载自blog.csdn.net/qq_40967086/article/details/128529370
今日推荐