C++ 炼气期之算术运算符
1. 前言
编写程序时,数据确定后,就需要为数据提供相应的处理逻辑(方案或算法)。所谓逻辑有 2 种存在形态:
抽象形态:存在于意识形态,强调思考过程,与具体的编程语言无关。具体形态:通过代码来实现。需要使用表达式描述完整的计算过程。
表达式由 2 个部分组成:
数据。也可称为操作数。运算符。运算符是计算机语言提供的能对数据进行基本运算操作的功能体。开发者在实现自己的逻辑运算时,需要组合这些运算符来描述自己的逻辑运算过程。
Tip: 可以把
C++的运算符看成一种特殊语法格式的函数,或把C++中的函数当成一种特殊的运算符。
在使用运算符时,需要遵守下面的 2个基本原则:
运算符对操作的数据有内置的类型要求。如数学运算符要求操作数是数字类型。- 如果
运算符需要多个操作数时,则要求数据类型必须相同。如果出现类型不一致时,编译器会试着把不同类型的数据转换成同类型的数据后再进行运算。开发者也可以显示进行强制类型转换。
2. 运算符种类
C++中的运算符非常多,如下是几类常用的运算符:
- 算术运算符。
- 逻辑、关系运算符。
- 赋值运算符。
- 递增、递减运算符。
- 成员访问运算符。
- 条件运算符。
- 位运算符。
sizeof运算符。- 逗号运算符。
使用运算符前,需要理解如下几个概念:
运算符的优先级: 不同类别中的
运算符的优先级是不相同的。当在一个表达式中出现多个运算符时,则需要根据运算符的优先级进行先后运算。运算符的操作数: 作用于一个操作数的运算符为
一元运算符,作用于两个操作数的运算符为二元运算符。C++中还有一个可作用于三个操作数的条件运算符。结合性: 当复杂表达式中的多个
运算符的优先级相同时,则要根据运算符的结合性进行运算。如100/4*8这个表达式,/和*的优先级是相同,因乘、除都是具有从左到右的结合性。所以先计算100/4=25再计算25*8。Tip: 只有当两个运算符作用于同一个操作数时,优先级和结合性才有意义。
C++中的基础运算符较多,且因C++是弱类型语言,每一种运算符在使用过程中都存在很多细节问题。算术运算符又是运算符中的基础运算符。
本文试图通过讲解清楚算术运算符,让阅读者了解使用C++运算符时应该注意的事项。
3. 算术运算符
3.1 功能描述
算术运算符用来对数字型数据进行数学语义上的加、减、乘、除。此类中有 5个运算符:
+:对2个数字类型的数据进行数学语义上的加法运算。-:对2个数字类型的数据进行数学语义上的减法运算。*:对2个数字类型的数据进行数学语义上的乘法运算。/:对2个数字类型的数据进行数学语义上的除法运算。%:取余或取模操作运算符。运算结果是两个操作数相除后的余数部分,不能用于浮点数据类型。
算术运算符是二元运算符。使用时,需要提供 2 个操作数。
3.2 运算符重载问题
C++可以重载运算符,所谓重载运算符,指同一个运算符可以根据使用时的上下文信息,表现出不同的运算能力。如-运算符, 当作为二元运算符时,用来对操作数进行相减操作。
int num1=30;
int num2=20;
//此处的 - 运算符表现出减法运算能力
int res=num1-num2;
cout<<res<<endl;
//输出结果: 10
当作为一元运算符时,则是取负的意思。如下代码:
int num=-10;
int num01=-num;
cout<<num01<<endl;
//输出结果为 10,负负为正
同理,
+运算符也存在重载。运算符重载是
C++中的一个特色。对于有符号数据类型而言,如果在字面常量前面没有显示提供
正、负符号,则默认为+(正)符号。
3.3 两数相除的问题
当/运算符作用于 2 个整型数字时,会得到舍弃小数点后的整数部分数值,或称为两数相除的商,意味着会丢失精度。
如下代码:
int num1=7;
int num2=3;
int res=num1/num2;
cout<<res<<endl;
//输出结果:2,丢失精度
如果要保留两个数字相除的精度,则应该以浮点数据类型的身份进行相除。
double num1=7;
double num2=3;
double res=num1/num2;
cout<<res<<endl;
//输出结果:2.33333
%运算符作用于 2 个整型类型的数据时,运算结果是 2 个数字相除之后的余数部分。如下代码:
int num1=5;
int num2=3;
int res=num1 % num2;
cout<<res<<endl;
//输出结果:2 。
%用于浮点数据类型相除时,会出现编译错误。也就是 %只能用于整型数据的运算,不能用于浮点数据类型。

3.4 关 于/和%运算符的正、负问题
- 当
2个操作数据都是正数时。
int num1=21;
int num2=8;
int res=num1 / num2;
cout<<" / 运算:"<<res<<endl;
res=num1 % num2;
cout<<" % 运算:"<<res<<endl;
/和%动算符的输出结果都是正数。
/ 运算:2
% 运算:5
- 当
2个操作数都为负数时。
int num1=-21;
int num2=-8;
int res=num1 / num2;
cout<<" / 运算:"<<res<<endl;
res=num1 % num2;
cout<<" % 运算:"<<res<<endl;
输出结果,一个是正数,一个是负数。
/ 运算:2
% 运算:-5
- 当
2个操作数中被除数为负,除数为正时。
int num1=-21;
int num2=8;
int res=num1 / num2;
cout<<" / 运算:"<<res<<endl;
res=num1 % num2;
cout<<" % 运算:"<<res<<endl;
输出结果都是负数。
/ 运算:-2
% 运算:-5
- 当
2个操作数中被除数为正,除数为负时。
int num1=21;
int num2=-8;
int res=num1 / num2;
cout<<" / 运算:"<<res<<endl;
res=num1 % num2;
cout<<" % 运算:"<<res<<endl;
输出结果为一负一正。
/ 运算:-2
% 运算:5
结论:
- 当
2个数字使用%运算符进行相除操作时,运算结果的正负号与num1操作数(被除数)的正负号保持一致。 /运算符运算结果的正负号和数学上的语义一致。两个操作数都为正或为负时则正正得正,负负得正。两个操作数为一正一负时:则正负得负。
3.5 数据溢出问题
在使用算术运算符时,有可能出现数据溢出现象。如下代码:
short num=32767;
short num01=num+1;
cout<<num01<<endl;
输出结果:
数字:-32768
无符号short(16位)的类型数据的最大值是 32767,在此数字上加一,num01的值理论是上 32768。但实际结果是 -32768。因为 32768已经超过short范围,编译器会重新计算出一个新的结果(并不是预期值)。这种现象叫数据溢出。
对于无符号 short,可以认为其有 2 部分,一部分为负数,一部分为正数。当正数溢出后,会进入负数部分。

如下代码,因溢出,超过了负数区域最小值,会溢出到正数区域。
short num1=-32768;
short num2=num1-1;
cout<<num2;
//输出结果:32767
数据溢出发生在当把数据类型范围大的数据存储到数据类型小的类型变量中时。
double数据存储到int类型变量中。int类型的数据存储到short类型变量中。long long int类型的数据存储到int类型变量中时。- ……
数学运算符也可以用于指针类型运算,因指针变量其数据本质就是数字数据。但指针变量不能用于乘法和除法,加、减的语义是指针的向前后后移动,乘法、除法没有语义价值。
3.6 类型转换
根据运算符的基本使用原则,要求所有操作数的类型必须相同。
有时,在一个表达式中,即使存在多个操作数的类型不一致,也能正常工作。那是因为,编译器会把不同的数据类型转换成一致,然后再进行运算。
由编译器完成的类型转换,称为自动(隐式)类型转换:
- 整型提升:
C++将bool、char、unsigned char、signed char和short值转换为int。这些转换被称为整型提升。 - 浮点提升:整型类型自动向浮点类型转换,如
int向double转换。这种转换是不会存在数据丢失问题,但会产生空间浪费。 - 向下缩窄: 当目标类型小于原类型时,如
double向int转换,int类型向short转换时,这种转换是可以的,但会发生数据丢失的情况。可能会得不到预期结果。
碗里的水倒到缸里,不会丢失水。
缸里面的水倒到碗里,如果缸里面的水很少,不够或者刚够一碗水,不会发生水丢失。但是,这里会有潜在丢失问题,因为生活常识告诉我们,缸里面的水往往是要超过一个碗所能盛下的容量。
所以,向下缩窄存在潜在的数据丢失风险。
如下代码,其中发生了 2 次自动类型转换,有数据丢失的潜在风险。
double num1=7;
int num2=3;
int res=num1/num2;
cout<<res<<endl;
//输出结果: 2
- 浮点提升:
num2中的数据会被转换成double数据类型,让右边的表达式符合同类型原则。此时,右边表达式运算后的结果类型为double。这一步不会发生数据丢失问题。 - 向下缩窄: 左边的
res变量类型为int,编译器会把右边的double类型结果转换成int。如果数值大于int类型范围时,则会出现丢失精度问题。
如下代码,则不会发生数据丢失问题:
double num1=7;
int num2=3;
double res=num1/num2;
cout<<res<<endl;
//输出结果:2.33333
如下的代码,也会发生自动类型转换。
int num1=20;
char num2='A';
int res=num1+num2;
cout<<res<<endl;
//输出结果: 85
char类型会转换成int类型。字符保存在计算机上时,需要对其进行数字编码,字符转换成int的数字是底层的编码数字。
如下代码,也会发生自动类型。
int num1=20;
bool num2=true;
int res=num1+num2;
cout<<res<<endl;
C++中,bool数据类型本质上就是int类型。true会转换为1。false会转换为0。
3.7 {}赋值语法
C++在进行自动类型转换时,如果目标类型小于原类型时,也是能够转换的,这种现象叫缩窄。缩窄会存在潜存数据安全问题。C++11提供了{}赋值语法,会对超过范围的缩窄进行编译提示。如下代码。
- 因
44555数字已经超过char范围,向下缩窄不被允许。
char c1= {44555};
- 因
X是一个变量,在运行时,x有可能被修改,并让其值大于char数字范围,向下缩窄不被允许。
int x=66;
char c4={x};
3.8 强制类型转换
C++允许开发者显式地进行类型转换。语法格式有 2 种:
- (目标类型名)变量。
- 目标类型名(变量)。
强制类型转换不会修改变量本身,而是创建一个新的值。用于表达式中进行计算。
double num1=23.6;
//C++强制类型转换语法
int num2=double(num1);
cout<<num2<<endl;
//C 强制类型转换语法
num2=(double)num1;
cout<<num2<<endl;
C++还提供了 4 个类型转换运算符,使得转换过程更规范。这里只做简要介绍,有兴趣者可以深入了解一下。
dynamic_cast。在类层次结构中进行向上转换。const_cast。用于执行只有一种用途的类型转换,即改变值为const或volatile。static_cast。只有当类型之间可以隐式转换时才能转换。reinterpret_cast。用于一些有很大潜在危险的类型转换。
3.9 auto 语法
auto关键字在C++的作用是自动类型推导。在声明变量时,可以使用 auto关键字,不指定变量的类型说明。编译器会根据变量中所存储的数据的类型自动推导出数据类型。
// num 是浮点数据类型
auto num=5.3;
//num1 是整型数据类型
auto num1=4;
如 Python、JS就是一种动态语言,表现在数据类型可以底层编译器自动识别。
虽然C++有 auto语法,但C++归属于弱类型语言,在数据类型识别上,一半依赖于开发者的语法约束,一半依赖编译器的自动识别。
4. 总结
因C++语言的开放性,数据类型的自我适应性非常灵活。在一个表达式,当出现类型不同的情况时,编译器会试图进行各种类型上的转换,让表达式符合类型相同的运算原则。
宽松的好处是速度快,但也会带来潜在的风险,开发者应该尽可能在语法上对数据类型进行约束,不要过于依赖编译器。养成良好的编码习惯。
C++ 炼气期之算术运算符的更多相关文章
- PHP中的运算符---算术运算符、逻辑运算符、赋值运算符、比较运算符
1.算术运算符 常见的算术运算符 运算类型 运算符 举例 结果 取反运算 - -$a 返回$a的负值 加法运算 + $a + $b 返回$a与$b的和 减法运算 - $a - $b 返回$a与$b的差 ...
- java中的算术运算符、赋值运算符、比较运算符、逻辑运算符、条件运算符
一.算术运算符 算术运算符主要用于进行基本的算术运算,如加法.减法.乘法.除法等. Java 中常用的算术运算符: 其中,++ 和 -- 既可以出现在操作数的左边,也可以出现在右边,但结果是不同滴 例 ...
- javascript运算符——算术运算符
× 目录 [1]一元加 [2]一元减 [3]递增[4]递减[5]加法[6]减法[7]乘法[8]除法[9]求余 前面的话 javascript中的算术操作主要通过算术运算符来实现,本文将介绍算术运算符的 ...
- javascript算术运算符详解
算术运算符 +.-.*./.%.++.-- ++.--分为前缀形式和后缀形式 前缀形式先加减1在执行 后缀形式先执行再加减1 注意 +号用来连接两个字符串 只要+连接的操作数中有一个是字符串型,JS就 ...
- 慕课网-安卓工程师初养成-3-2 Java中的算术运算符
来源:http://www.imooc.com/code/1279 算术运算符主要用于进行基本的算术运算,如加法.减法.乘法.除法等. Java 中常用的算术运算符: 其中,++ 和 -- 既可以出现 ...
- JAVA算术运算符、关系运算符和位运算符
算术运算符 1.java的算数运算符包括+(加).-(减).*(乘)./(除).%(取余),在运算过程中出现的隐式转换原则和C语言一样:2. 高位数据向低位数据转化要使用强制转化: 关系运算符 1.j ...
- Java SE ---算术运算符
算术运算符:(加)+,(减)-,(乘)*,(除)/,(求余)%,自增自减 一,算数运算符:当有若干个变量参与运算时,结果类型取决于这些变量中表示范围最大的那个变量类型.如果参加运算的变量中有整型int ...
- c语言学习之基础知识点介绍(四):算术运算符和逗号表达式
本节主要介绍c语言中运算符. 运算符主要分为四类: 1.算术运算符 加(+),减(-),乘(*),除(/),取余(%,两数相除,得到余数) 2.关系运算符 3.逻辑运算符 4.换位运算符 下面将依次介 ...
- Python算术运算符
Python 运算符 什么是运算符? 本章节主要说明Python的运算符.举个简单的例子 4 +5 = 9 . 例子中,4和5被称为操作数,"+"号为运算符. Python语言支持 ...
随机推荐
- LC-209
给定一个含有 n 个正整数的数组和一个正整数 target . 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, nums ...
- 轻量化安装 TKEStack:让已有 K8s 集群拥有企业级容器云平台的能力
关于我们 更多关于云原生的案例和知识,可关注同名[腾讯云原生]公众号~ 福利: ①公众号后台回复[手册],可获得<腾讯云原生路线图手册>&<腾讯云原生最佳实践>~ ②公 ...
- 启动分区查找可以通过 fdisk -l命令
这里有两个硬盘,一个硬盘有两个分区,sda1 的boot列 带*表示是启动分区,否则为空
- MySQL事务提交流程详解
MySQL事务的提交采用两阶段提交协议, 前些日子和同事聊的时候发现对提交的细节还是有些模糊,这里对照MySQL源码详细记录一下,版本是MySQL5.7.36. 一. 事务的提交流程. 1. 获取 M ...
- 超越iTerm! 号称下一代终端神器,功能贼强大!
程序员的一生,用的最多的两个工具,一个是代码编辑器(Code Editor),另外一个就是命令行终端工具(Terminal).这两个工具对于提高开发效率至关重要. 代码编辑器在过去的 40 年里不断进 ...
- 自增特性,外键,级联更新与级联删除,表间关系,SELECT用法,GROUP BY
自增特性 自动增长的作用: 问题:为数据表设置主键约束后,每次插入记录时,如果插入的值已经存在,会插入失败. 如何解决:为主键生成自动增长的值. 自动增长的语法: 字段名 数据类型 AUTO_INCR ...
- 最新管家婆财贸ERP C9 V22.0的应用网页版的财务软件1000用户补丁免狗授权注册机网络版软件下载
管家婆财贸ERPC9应用价值: 1.多组织独立核算 多种组织形态核算,出具独立的三大财务报表及业务报表,发挥经营管理的积极性,便于专业化运营. 2.兼顾统筹与分权 满足多种集团统管与分权管控模式需求, ...
- 无线:NB-IoT
一. NB总体网络架构 NB-IoT端到端系统架构如下图所示: 终端:UE(User Equipment),通过空口连接到基站(eNodeB(evolved Node B , E-UTRAN 基站)) ...
- linxu篇-centos搭建ftp服务器
1安装vsftpd 2备份配置文件 3修改配置文件 vi /etc/vsftpd/vsftpd.conf anonymous_enable=NO #允许匿名用户访问为了安全选择关闭 local_ena ...
- Python数据分析--Numpy常用函数介绍(2)
摘要:本篇我们将以分析历史股价为例,介绍怎样从文件中载入数据,以及怎样使用NumPy的基本数学和统计分析函数.学习读写文件的方法,并尝试函数式编程和NumPy线性代数运算,来学习NumPy的常用函数. ...