IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 【手把手带你入门】操作符详解和表达式求值 -> 正文阅读

[C++知识库]【手把手带你入门】操作符详解和表达式求值

在这里插入图片描述


在初识C语言中(下)中,我们已经对操作符进行了一些介绍,今天的这篇博客主要对一些操作符进行更详细的介绍,并且对表达式求值这一块的内容进行讲解。

操作符详解

以下提到的操作符如果在【手把手带你入门】初识C语言(下)中已提及,则这里不再重复赘述。

算术操作符

在这里插入图片描述
注意:

  1. 上述五个操作符为算术操作符,其中%操作符只能作用于整数,返回的是两数整除之后的余数。其他四个操作符既可作用于整数,也可作用于浮点数。
  2. 对于/操作符,如果两个操作数都为整数,则执行整数除法。当操作数中有浮点型操作数时,执行浮点数除法,返回类型为浮点型。

移位操作符

在这里插入图片描述
移位操作符,移动的是二进制位。
对于整数的二进制位有3种表示形式:原码、反码、补码。

对于正数:原、反、补码相同
对于负数:
原码 - 直接按照数字的正负写出的二进制序列
反码 - 原码的符号位不变,其他位按位取反
补码 - 反码+1
整数在内存中存储的是二进制的补码

如果我们计算5<<1:
在这里插入图片描述
如果计算-1<<1
在这里插入图片描述
所以 -1 << 1 = -2。

综上,我们可以说左移是二进制序列向左向左移动,低位补0。那么右移操作符呢?同理右移操作符应该是向右移动,高位补上一个0或1。

但是二进制序列的高位是符号位,所以我们右移之后,高位是符号位,这时候应该补什么呢?

其实右移分为逻辑移位和算数移位:

逻辑右移 - 右边丢弃,左边补0
算术右移 - 右边丢弃,左边补原符号位

对于整数来说,逻辑右移和算术右移是一样的。

那么对于负数呢?我们还是用-1来进行计算
在这里插入图片描述
那么对于编译器来说,执行的是算术右移还是逻辑右移呢?

我们只要进行一下计算,看看得到的结果是什么就知道啦!
在这里插入图片描述
所以当前编译器(VS2019)采用的是算术右移。
并且绝大多数的编译器进行的都是算术右移。

注意:对于移位操作符,不要移动负数位,这是标准未定义的。
在这里插入图片描述
因为它表达的意思很难理解,向右移动-1位是表示向左移动一位的意思吗?还是有其他的意思呢?

这种写法在C语言中没有规定,不同的编译器下也可能会有不同的理解,所以我们在写代码的时候要注意,这样写是不合法的。

另外,移位操作符只作用于整型,所以不论是被移位的数,还是移动的位数,都应该是一个整数。

位操作符

在这里插入图片描述
位操作符,实际上是按二进制位进行操作的,所以他们的操作数都必须是整数。

接下来我们还是用一组数来举例:
a=3 b =-2
首先我们分别写出a和b的补码:
在这里插入图片描述
a&b:
在这里插入图片描述
a|b:
在这里插入图片描述

a^b:
在这里插入图片描述
那么这些操作符有什么用呢?

例:当我们想看看15的二进制序列的最低位是多少时:
在这里插入图片描述
还有更多的应用:
比如计算一个数的二进制序列中有多少个1(结合&和>>操作符);再比如用来判断一个是奇数还是偶数等等。

一道面试题:不能创建临时变量(第三个变量),实现两个数的交换。
在这里插入图片描述
在这里插入图片描述
我们可以认为,a ^ b是一个密码。
密码 ^ a就能得到b
密码 ^ b就能得到a

我们还能拓展:

a ^ a=0
0 ^ a=a

a ^ a ^ b=b
a ^ b ^ a=b

因此,我们可以认为^(异或)是支持交换律的
但是我们在日常进行两数交换的时候,还是创建临时变量的方法最好,因为异或的方法有两个局限性:

  1. 可读性不高
  2. 只适用于整型

赋值操作符

赋值操作符:=
在这里插入图片描述
上图写法属于连续赋值,在C语言的语法上是支持的。

但是我们应尽量减少这样写,因为分开写能使我们的代码更简明易懂,并且易于调试。
在这里插入图片描述
例如:
a>>=1 即 a=a>>1
这样写能使我们的代码更简洁方便,两种方法都可行。

单目操作符

单目操作符就是只有一个操作数的操作符。
在这里插入图片描述
&操作符:
在这里插入图片描述
sizeof操作符:
sizeof是单目操作符,用于计算变量或者类型创建变量的内存大小(单位是字节),和内存中存放着什么数据没有关系。
在这里插入图片描述
在这里插入图片描述

sizeof和数组

在这里插入图片描述

关系操作符

在这里插入图片描述
关系操作符虽然比较简单,但是我们要注意关系操作符的使用要符合逻辑,避免陷阱。比如在判断相等时把“==”写成“=”。

逻辑操作符

在这里插入图片描述
注意:逻辑操作符只关注真假。
在这里插入图片描述
在这里插入图片描述

条件操作符

条件操作符:exp1 ? exp2 : exp3

注意,这是C语言中唯一的一个三目操作符,整体是一个表达式。

表达式1的结果如果为真,则表达式2的结果是整个表达式的结果,否则表达式3的结果是整个表达式的结果。

逗号操作符

由逗号(,)隔开的一串表达式就是逗号表达式。

逗号表达式会从左向右一次计算,整个逗号表达式的结果是最后一个表达式的结果。

逗号表达式可以这样写:
在这里插入图片描述
也可以这样写:
在这里插入图片描述
对比以下两段代码:
在这里插入图片描述

下标引用、函数调用和结构成员

在这里插入图片描述
在这里插入图片描述
根据上图,我们应该深刻理解[ ]仅仅是一个操作符,而arr和i是[ ]的两个操作数。

而对于函数调用操作符来说,它可以接收一个或多个操作数,其中第一个操作数是函数名,剩余的操作数是传递给函数的参数。

结构成员访问操作符:
结构体变量.成员名
结构体指针->成员名
在这里插入图片描述

表达式求值

结合之前的文章和以上的内容,我们对于C语言中的操作符已经有了一个全面的理解。那么在使用的过程中,操作符是如何影响表达式求值的呢?

我们接下来探讨一下这个问题。

表达式求值的时候受求值顺序的影响,而这些顺序有时候是由操作符的优先级和结合性决定的。

另外,有些表达式的操作数在求值的过程中可能会发生类型的转换,这也会影响表达式的运算。

隐式类型转换

在运算的过程中,可能会存在某些类型转化,是不加任何提示的,自动地悄悄地进行的,这种类型转换我们称之为隐式类型转换。

整型提升

C的整型算术运算总是至少以缺省整型类型的精度来进行的。

为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升。

在这里插入图片描述

那么为什么要进行整形提升呢?

这是因为,表达式的整型运算要在CPU的相应运算器件中执行,而CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器长度。

通用CPU是难以直接实现两个8比特字节的直接相加运算(虽然机器指令中可能有这种字节相加指令)。

所以,即使是两个char类型的操作数进行运算,在CPU中执行时也要先转换为CPU内整形操作数的标准长度(提升为int或者unsigned int),然后再执行运算。

那么在运算过程中,是如何进行整型提升的呢?

整型提升是按照变量类型的符号位来提升的
即:如果是负数,则高位补1,如果是正数和无符号数,则高位补0

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

算术转换

除了整型提升,还有一种转换叫算术转换。

即如果一个表达式中有两个不同类型的操作数要进行运算,那么其中一个操作数就会被转换为另一个操作数的类型,这种转换就称为算术转换。

long double
double
float
unsigned long int
long int
unsigned int
int

以上类型的精度从上往下依次降低,所以如果某个操作数在运算时精度较低,则会被算术转换为另一个精度更高的操作数的类型。
在这里插入图片描述

操作符的属性

其实操作符除了以上两种隐式类型转换,还有以下三种影响表达式求值的因素。

  1. 操作符的优先级
  2. 操作符的结合性
  3. 是否控制求值顺序

两个相邻的操作符先执行哪个?

取决于他们的优先级。

如果两者的优先级相同,则取决于他们的结合性。

在这里插入图片描述
在这里插入图片描述
第三个因素:是否控制求值顺序。

大部分的操作符都是不控制求值顺序的,只有以下4个操作符控制求值顺序:

逻辑与 &
逻辑或 |
条件操作符 ? :
逗号操作符 ,

逻辑与:当表达式的左边为假时,整个表达式的结果为假,后面的表达式就不用计算了。

逻辑或 :当表达式的左边为真时,整个表达式的结果为真,后面的表达式也不用计算了。

条件操作符:当第一个表达式的结果为真时,第二个表达式的结果为整个表达式的结果,否则第三个表达式的结果为整个表达式的结果。也控制了表达式的求值顺序。

逗号表达式:虽然表达式从左往右依次计算,但是最后一个表达式的结果才是整个表达式的结果。这也被认为是控制了求值顺序。

但是我们要注意,并不是只要掌握了表达式的优先级、结合性等等属性和隐式类型转换,我们在写表达式的时候仍然要注意,避免写出一些有问题的表达式。

比如下面这段代码:
在这里插入图片描述
只要代码的执行路径不是唯一的,就是一段有问题的代码。

像上面的这段代码,我们完全可以把它分开来写,让代码简单明晰。

在这里插入图片描述
同样地,以下这段代码在不同的编译器下会计算出不同的结果。
在这里插入图片描述
因为这段代码拥有的计算路径不唯一,当不同的编译器进行计算的时候,他们执行计算的路径就可能不一样,因此产生出不同的结果。

所以,即使我们掌握了各种操作符的使用方法和注意事项,仍然要注意,永远不要写出上面这些有问题的代码噢~

今天的文章就到这里啦!~

你学废了吗???

如果你觉得文章还不错,给博主点个赞鼓励一下吧!
在这里插入图片描述

关注我,一起精进C语言吧!
在这里插入图片描述
相关代码已提交至Gitee了,按需自取噢!

https://gitee.com/fang-qiuhui/my-code/blob/my_code/blog_2021_8_24_operator/blog_2021_8_24_operator.c

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-26 11:56:22  更:2021-08-26 11:58:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 17:09:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码