操作符(原码反码补码)

目录

前言:

原反补码:

位操作符:

 ^

>>

<<

总结: 

逻辑操作符

&&

|| 

其他操作符: 

sizeof

++ 

-- 

()

?:(三目操作符)

,(逗号运算符)

+=

%

整形提升

练习巩固: 


 

前言:

  我们学习编程语言就必须会里面的所有操作符,在了解操作符之前需要有一些基础知识,我们必须要了解这些知识才能更好的去看其他内容。

  那么接下来我就一一详细介绍,有特别需求者可以直接跳转目录。

原反补码:

  我们知道内存里面存放的是二进制数据,内存记录的是二进制,B是电脑存储的基本单位(字节),1字节有8个比特位,就是8个二进制序列。如下:

1B  =8bit=8比特

1KB=1024B=1024字节

1MB=1024KB=1,048,576字节

1GB=1024MB=1,073,741,824字节

1TB=1024GB=1,099,511,627,776字节

1PB=1024TB=1,125,899,906,842,624字节

1EB=1024PB=1,152,921,504,606,846,976字节

1ZB=1024EB=1,180,591,620,717,411,303,424字节 

1YB=1024ZB=1,208,925,819,614,629,174,706,176字节 

  如int类型,有4个字节,32个比特位。但是负数该如何表示呢?

       于是就把最高位代表符号位,1代表负数,0代表正数。我们一般定义的int a = 1,C语言已经默认是有符号的整形。

       进入正题,原码、反码和补码到底是什么呢?在内存中存储的数据其实是以补码的方式存在的,因为计算机其实只会加减和位运算,为了解决负数的计算不会出错,就发明了补码(具体原因可以暂时忽略)。

  1. 原码:将一个数字以二进制记录,最高位是符号位,负数的最高位是1,正数的最高位是0。
  2. 反码:符号位不变,其他位按位取反。
  3. 补码:将反码加1。

       我们来看看-1在内存中是如何占据的:

       地址为方便表示将一个16进制位代表8个bit位(不影响阅读,详情请看进制的转换-CSDN博客)。 此时你就会考虑到,既然int有4个字节,32个比特位,那么如果把这32位全部填充成1是不是会有上限?明确的告诉你,确实如此。

       我们可以看到,当32位全部填充成1时,最大10进制无符号数整形(unsigned int)就保存的是4294967295。但是前面说最高位是符号位,我们一般定义的默认就是有符号的整形(signed int),那么如果最高位是0(就是正数),最高位就是少了一个1。

       所以看出整形保存的正数最大存储的数据是2147483647。关于原反补码的转换也有快捷方式,我们也可以将补码直接符号位不变,其他位按位取反以后加1直接得到原码,如下图:

(声明:补码的出现是为了负数方便计算,所以正数的原、反、补码相同)

       有了以上基础,我们就可以无障碍阅读一下内容了。 

位操作符:

  这个操作符有两种意思。

  1. 按位与:位操作符,与数学中的与相似,两真则真,一假则假(真可以理解为1,假可以理解为0)。遇到负数时先转化为补码,之后按位与。如图(负数与正数按位与)
  2. 取地址:因为每个变量在计算机中都有存储的空间,所以就有对应的地址编号(暂不用了解,涉及指针,详情请看指针(基础篇)-CSDN博客,也可以跳过,不影响阅读),此时就不再是位操作符。

  按位或:位操作符,一真则真,遇到负数时转化为补码,之后按位或。

 ^

  按位异或:位操作符,相同出零,相异出一。

 按位取反 :对一个数进行操作,是针对二进制位进行操作。

//这里可以忽略Printf的具体实现
void Printf(int a)
{
	int count = 32;
	while (count--)
	{
		printf("%d", (a >> count) & 1);
	}
}

int main()
{
	int a = 5;
	//对应的二进制位
	//00000000000000000000000000000101
	//~就是每一位取反
	//11111111111111111111111111111010

	//为方便讲述
	//此时我们使用函数打印其二进制序列
    //注:这不是printf函数
	Printf(~a);
	return 0;
}

>>

  右移操作符:将二进制位整体向右移,分为两种情况。

  • 算术右移:右边丢弃,左边补原符号位。通常是采用算数右移,右移时,先将数字转化为补码,之后右移,符号位不变,此时为转化后的补码,再将它转化为原码,得到二进制数,之后看符号位,将其转化为十进制即可。如图

       每当我们右移一位时,和十进制规律一样,该数会2倍缩小。

  • 逻辑右移:右边丢弃,左边补零。因为一般不会使用逻辑右移,所以我们不再举例。

       到底是算术右移还是逻辑右移,是取决于编译器,大部分编译器上是算术右移。

<<

       对应的,该操作符是左移操作符,但是它没有像右移操作符一样分为逻辑左移和逻辑右移,只要进行左移,先将其转换为补码,之后最高位不变,左边补0即可。该数呈2倍增长。

       关于左右移万万不可移动负数位。 

总结: 

       要想学好位操作符就一定要学好原反补码,这样才能更好的学习C语言。位操作符都是按照补码进行位操作的,同理,结果也是补码,所以要转换为原码得出正确结果。按位取反包括符号位。

       这里我们结合其他操作符来使用其他例子帮助小伙伴来更好的理解。

逻辑操作符

&&

       逻辑与:逻辑操作符,一假则假,1&&0结果为0,5&&0结果为0,5&&3结果为1。

|| 

        逻辑或:逻辑操作符,一真则真,5||0结果为1。

其他操作符: 

sizeof

       ???这也算操作符?是的,它是函数也是操作符,计算该数据类型的大小。计算结果为无符号的整形。

++ 

       ++可以理解为自增操作符,分为前置++和后置加加。

  • 前置++:先将该数自增1,之后赋值。
    int main()
    {
    	int a = 0, b = 0;
    	b = ++a;
    	//此时先执行++a,就是将a自增1
    	//之后赋值给b
    	printf("b = %d\n", b);
    	printf("a = %d\n", a);
    
    	return 0;
    }

  • 后置++:先使用该数原本的值,之后该语句结束执行完成后,自增1。
    int main()
    {
    	int a = 0, b = 0;
    	b = a++;
    	//此时先将a的值赋给b
    	//之后将a自增1
    	printf("b = %d\n", b);
    	printf("a = %d\n", a);
    
    	return 0;
    }

-- 

       也是分为 前置-- 和 后置--,其规则和 ++ 一样,这里我们不再过多赘述。

()

       注意,这也是一个操作符,是强制类型转换操作符。比如将浮点型类型强制转换为整形。

?:(三目操作符)

       什么东西?问号指数:满天星!这其实是三目操作符,它里面必须有变量。

       这其实是条件操作符:也称三目操作符,如a>b?a:b翻译的结果就是a>b吗?是大于b,就是a,否则就是b(记住是冒号)。

int main()
{
	//条件操作符/三目操作符
	int a = 10, b = 20;
	int max = 0;
	max = (a > b ? a : b);
	//翻译:a大于b吗?
	//大于b则max = a
	//小于b则max = b   
	printf("%d", max);
	return 0;
}

,(逗号运算符)

       从左到右依次进行,整个表达式的结果是最后一个表达式的结果。

int main()
{
	int a = 1, b = 2;
	int c = (a > b, a = b + 10, a, b = a + 1);
	printf("%d\n", c);
	return 0;
}

       这个操作符有两种意思。

  • 定义指针变量操作符:定义一个指针类型的变量。
  • 解引用操作符:若已经定义过指针变量,想通过该指针变量去访问指向的空间,就需要解引用。(详情请看指针(基础篇)-CSDN博客不影响阅读该文章)。

+=

       这个操作符其实就是……上图吧:

       当然其他的操作符也有这种用法。 

       这里还有很多类似的操作,我们不再一一赘述。 

%

       取模:其实就是除法取余数。

       负数也有取模规则,结果有第一个数的正负而定。 

整形提升

       我们知道字符在内存中也是2进制序列,那么计算机到底是如何进行字符的操作呢?比如定义的是字符型,输出的是整形,就会有暗箱操作。

        表达式的整形运算要在CPU的响应预案算起件内执行,CPU内整型元算器的操作数的字节长度一般就是int的字节长度,同时也是CPU通过寄存器的长度。

       因此即使两个char类型相加,也是难以直接实现两个8bit位直接相加运算(虽然机器指令中可能有这种bit位相加的指令),所以表达式中各种长度小于int的整型值,都必须先转换为int或unsigned int,然后才送去CPU执行运算。

       在整形提升时,char是8个比特位,有符号的情况下最高位被当为符号位。

int main()
{
	char a = -160;
	//10000000000000000000000010100000-原码
	//11111111111111111111111101011111-反码
	//11111111111111111111111101100000-补码
	//char只能访问1个字节01100000
	//最高位被当为符号位,打印的是整形,前面补符号位
     //00000000000000000000000001100000
	printf("%d\n", a);
	return 0;
}

  

       即使是有符号的整形,在整形提升时,也是按照最高位提升。

int main()
{
	char a = -1;
	signed char b = -1;
	//有符号数补码全为1,取1个字节
	//最高位为1,打印整形,前面补1,补码,换为原码为-1
	unsigned char c = -1;
	//无符号,-1补码还是全1,取1个字节
	//虽然最高位是1,但是无符号,前面补0
	printf("a=%d,b=%d,c=%d", a, b, c);
	return 0;
}

练习巩固: 

       其实和我们学的数学的加减乘除一样,这些操作符也是有优先级的。而且像读文章一样,我们是从左向右去读文章的,所以计算也大多是从左向右开始计算的,这称之为操作符的结合性。

       像有一些垃圾书籍总喜欢在这上面大做文章,出类似以下的出生代码:

        我们可以看到在各个编译器下结果不同,因为你无法确定执行的--和++哪一次结果是保留的,下面来看一些正常的练习。 

int main()
{
	int i = 0, a = 0, b = 2, c = 3, d = 4;
	i = a++ && ++b && d++;
	printf("a=%d\nb=%d\nc=%d\nd=%d\n", a, b, c, d);
	return 0;
}

int main()
{
	int i = 0, a = 0, b = 2, c = 3, d = 4;
	i = a++ || ++b || d++;
	printf("a=%d\nb=%d\nc=%d\nd=%d\n", a, b, c, d);
	return 0;
}

       最后,我们给出每个操作符的优先级顺序: 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/224308.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据仓库与数据挖掘复习资料

一、题型与考点[第一种] 1、解释基本概念(中英互译解释简单的含义)&#xff1b; 2、简答题(每个10分有两个一定要记住)&#xff1a; ① 考时间序列Time series(第六章)的基本概念含义解释作用&#xff08;序列模式挖掘的作用&#xff09;&#xff1b; ② 考聚类(第五章)重点考…

Redis7--基础篇7(哨兵sentinel)

1. 关于哨兵的介绍 1、监控redis运行状态&#xff0c;包括master和slave&#xff08;主从监控&#xff09; 2、哨兵可以将故障转移的结果发送给客户端&#xff08;消息通知&#xff09; 3、当master down机&#xff0c;能自动将slave切换成新master&#xff08;故障转移&#…

STM32——电动车报警器

项目设计 // 如果检测到 PA4 被拉低&#xff08;小偷偷车&#xff09;&#xff0c;并且警报模式打开 // 则将 PB7 拉低&#xff0c;继电器通电&#xff0c;喇叭一直响 // 如果检测到 PA5 被拉高&#xff08;按键 A 按下&#xff09;&#xff0c;设定为开启警报模式 // 则将…

Python计算方差

方差可以反应变量的离散程度&#xff0c;是因为它度量了数据点与均值的差异。方差是每个数据点与均值的差的平方和的平均值&#xff0c;它可以反映数据点在均值附近的分布情况。如果方差较小&#xff0c;说明数据点更加集中在均值附近&#xff0c;离散程度较小&#xff1b;如果…

什么是神经网络的超参数

1 引言 超参数在神经网络的设计和训练中起着至关重要的作用。它们是在开始训练之前设置的参数&#xff0c;与网络的结构、训练过程和优化算法有关。正确的超参数选择对于达到最优模型性能至关重要。 2 神经网络结构的超参数 层数&#xff08;Layers&#xff09;&#xff1a; 决…

基于STM32 IAP技术的物联网设备固件更新应用研究

本文将深入研究基于STM32 IAP技术的物联网设备固件更新应用。首先&#xff0c;我们会介绍物联网设备固件更新的重要性和挑战。然后&#xff0c;我们将详细讲解STM32 IAP技术的原理和实现方式。接下来&#xff0c;我们会通过一个代码示例演示如何使用STM32 IAP技术实现物联网设备…

搭建个人网盘应用Nextcloud

使用DNF管理软件包 1 使用winscp工具将openeuler-20.03-LTS-x86_64-dvd.iso上传至openeuler虚拟机的/root目录下&#xff0c;然后执行如下命令挂载ISO [rootopenEuler ~]# mount -o loop /root/openEuler-20.03-LTS-everything-x86_64-dvd.iso /mnt/2 添加软件源 [rootope…

联合基于信息论的安全和隐蔽通信的框架

这个标题很帅 abstractintroductionsystem modelPROPOSED JOINT OPTIMIZATION OF ITS AND COVERT TRANSMISSION RATE信息论安全 &#xff08;ITS&#xff09;隐蔽通信需要&#xff08;CC&#xff09; Joint Information-Theoretic Secrecy and Covert Communication in the Pre…

AWS Remote Control ( Wi-Fi ) on i.MX RT1060 EVK - 2 “架构 AWS”

接续上一章节&#xff0c;我们把开发环境架设好之后&#xff0c;此章节叙述如何建立 AWS IoT 环境&#xff0c;请务必已经有 AWS Account&#xff0c;申请 AWS Account 之流程将不在此说明。 III-1. 登入AWS IoT&#xff0c; 在“管理”>“所有装置”>“实物”下点击“建…

VS2019 下配置 OpenCV4.6.0 库

一、编辑电脑系统环境变量。 二、打开 VS2019 新建一个C项目。 1.进行Debug和Release的配置 X64 平台。 2.属性配置&#xff1a;VC目录 -> 包含目录 3.属性配置&#xff1a;VC目录 -> 库目录 4.属性配置&#xff1a;链接器 -> 输入 -> 附加依赖项 带 d 的 .lib 为 …

Web开发学习HTTP协议、通过浏览器控制台学习HTTP协议。

文章目录 HTTP协议1.HTTP协议是什么&#xff1f;2.HTTP协议的特点3.什么是URL?4.通过浏览器控制台学习HTTP协议Request Headers请求数据格式说明Response Headers请求数据格式说明 5.HTTP工作原理 HTTP协议 1.HTTP协议是什么&#xff1f; HTTP协议是一种超文本传输协议&…

合并PDF(将多个pdf文件整合成一个pdf文件)

推荐使用下面这个免费在线的PDF文件合并工具&#xff0c;简单且易操作。 合并PDF - 在线上免费合并PDF文件 (smallpdf.com) 还有其他功能&#xff0c;不过现在我尚未使用其他功能&#xff1a; 关于费用&#xff1a;

Python 云服务器应用,Https,定时重启

Python 云服务器应用,Https,定时重启 环境搭建Python模块模块导入生成Flask实例GET处理启动服务器打开网页验证 GET接入证书 支持https申请证书下载证书保留 xxx.crt 和 xxx.key文件就可以了 copy到python项目目录ssl_context 配置 宝塔面板操作在www目录下新建python工作目录在…

Python实现FA萤火虫优化算法优化LightGBM回归模型(LGBMRegressor算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 萤火虫算法&#xff08;Fire-fly algorithm&#xff0c;FA&#xff09;由剑桥大学Yang于2009年提出 , …

【力扣】240.搜索二维矩阵

题目意思是从该矩阵之中查找出是否有和target一样的值&#xff0c;若有则返回true&#xff0c;无则返回false。这里我用的是java。总共有三种方法&#xff0c;分别是暴力解题法&#xff08;能过&#xff09;&#xff0c;二分查找法&#xff08;就是将二维数组拆分成m个二维数组…

NDIS协议驱动开发指南

文章目录 NDIS协议驱动开发指南1. 技术概览2. NDIS协议驱动2.1 BindAdapterHandlerEx2.2 SendNetBufferListsCompleteHandler2.3 ReceiveNetBufferListsHandler2.4 ProtocolNetPnpEvent 3. NET_BUFFER_LIST4. ndisprot实例5. 总结 NDIS协议驱动开发指南 我们知道&#xff0c;在…

三十八、AT模式

目录 一、定义 1、AT模式工作原理如下&#xff1a; 2、优点&#xff1a; 3、缺点&#xff1a; 4、流程&#xff1a; 二、AT模式与XA模式的区别 三、AT模式的脏写问题 四、实现AT模式 一、定义 AT模式是指使用AT命令进行串口通信的工作模式。AT命令是由两个字符组成的命…

Kubernetes(K8s)DashBoard的使用-11

DashBoard 之前在kubernetes中完成的所有操作都是通过命令行工具kubectl完成的。其实&#xff0c;为了提供更丰富的用户体验&#xff0c;kubernetes还开发了一个基于web的用户界面&#xff08;Dashboard&#xff09;。用户可以使用Dashboard部署容器化的应用&#xff0c;还可以…

redis应用-分布式锁

目录 什么是分布式锁 分布式锁的基本实现 引入过期时间 引入校验id 引入lua 引入看门狗 引入redlock算法 什么是分布式锁 在一个分布式系统中,也会涉及到多个节点访问同一个公共资源的情况,此时就需要通过锁来做互斥控制,避免出现类似于"线程安全"的问题. 而…

2023_Spark_实验二十七:Linux中Crontab(定时任务)命令详解及使用教程

Crontab介绍&#xff1a; Linux crontab是用来crontab命令常见于Unix和类Unix的操作系统之中&#xff0c;用于设置周期性被执行的指令。该命令从标准输入设备读取指令&#xff0c;并将其存放于“crontab”文件中&#xff0c;以供之后读取和执行。该词来源于希腊语 chronos(χρ…