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++boolcharunsigned charsigned charshort值转换为 int。这些转换被称为整型提升。
  • 浮点提升:整型类型自动向浮点类型转换,如 intdouble转换。这种转换是不会存在数据丢失问题,但会产生空间浪费。
  • 向下缩窄: 当目标类型小于原类型时,如doubleint转换,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会转换为 1false会转换为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。用于执行只有一种用途的类型转换,即改变值为 constvolatile
  • static_cast。只有当类型之间可以隐式转换时才能转换。
  • reinterpret_cast。用于一些有很大潜在危险的类型转换。

3.9 auto 语法

auto关键字在C++的作用是自动类型推导。在声明变量时,可以使用 auto关键字,不指定变量的类型说明。编译器会根据变量中所存储的数据的类型自动推导出数据类型。

// num 是浮点数据类型
auto num=5.3;
//num1 是整型数据类型
auto num1=4;

PythonJS就是一种动态语言,表现在数据类型可以底层编译器自动识别。

虽然C++auto语法,但C++归属于弱类型语言,在数据类型识别上,一半依赖于开发者的语法约束,一半依赖编译器的自动识别。

4. 总结

C++语言的开放性,数据类型的自我适应性非常灵活。在一个表达式,当出现类型不同的情况时,编译器会试图进行各种类型上的转换,让表达式符合类型相同的运算原则。

宽松的好处是速度快,但也会带来潜在的风险,开发者应该尽可能在语法上对数据类型进行约束,不要过于依赖编译器。养成良好的编码习惯。

C++ 炼气期之算术运算符相关推荐

  1. 【JavaSE】算术运算符、关系运算符、逻辑运算符、赋值运算符与三元运算符

    本专栏为 JavaSE 的学习笔记及相关项目,专栏长期免费更新 ❤️ ❤️ ❤️ ⭐️往期回顾: [JavaSE]String类与基本数据类型转换 [JavaSE]Java数据类型.变量基本使用.编码 ...

  2. 【Python学习笔记】第一章基础知识:格式化输出,转义字符,变量类型转换,算术运算符,运算符优先级和赋值运算符,逻辑运算符,世界杯案例题目,条件判断if语句,猜拳游戏与三目运算符

    Python学习笔记之[第一章]基础知识 前言: 一.格式化输出 1.基本格式: 2.练习代码: 二.转义字符 1.基本格式: 2.练习代码: 3.输出结果: 三.输入 1.基本格式: 2.练习代码: ...

  3. Go 学习笔记(5)— 算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符、取地址和指针运算符

    1. Go 运算符分类 Go 语言内置的运算符有: 算术运算符 关系运算符 逻辑运算符 位运算符 赋值运算符 其他运算符 1.1 算术运算符 下表列出了所有Go语言的算术运算符.假定 A 值为 10, ...

  4. SQL基础学习总结:3(select语句基础算术运算符比较运算符)

    select语句基础 列的查询 从表中选取数据时需要使用select语句,通过select语句查询并选取出必要数据的过程称为匹配查询或查询. 语法结构如下: select <列名1>,&l ...

  5. sql算术运算符_SQL运算符教程–按位,比较,算术和逻辑运算符查询示例

    sql算术运算符 At its core, the internet and all its applications are just data. 互联网及其所有应用程序的核心只是数据. Every ...

  6. Python算术运算符及用法详解

    算术运算符也即数学运算符,用来对数字进行数学运算,比如加减乘除.下表列出了 [Python] 支持所有基本算术运算符. 接下来将对表 1 中各个算术运算符的用法逐一讲解. + 加法运算符 加法运算符很 ...

  7. C++算术运算符与算术表达式

    C++中的算术运算符包括基本的算术运算符和自增.自减运算符.由算术运算符.操作数和括号构成的表达式称为算术表达式.

  8. 算术表达式求解背景_1.8 C++算术运算符与表达式

    点击上方"C语言入门到精通",选择置顶 第一时间关注程序猿身边的故事 作者 闫小林 白天搬砖,晚上做梦.我有故事,你有酒么? 基本的算术运算符 在上一节大概介绍了算术运算符有哪些, ...

  9. python的算术运算符不包括_没有算术运算符的A + B,Python与C ++

    我试图解决一个老问题: 编写一个将两个[整数]数字A和B相加的函数.不应使用+或任何算术运算符. 对于任意底数的a + b,我们可以将加号视为两个部分:1. a + b,不带进位:2. + b产生的进 ...

最新文章

  1. POJ 1821 Fence ★(单调队列优化DP)
  2. JavaScript——易班优课YOOC课群课程视频立刻完成解决方案
  3. (周日赛)Sort the Array
  4. 里面怎么定义变量_小哥今天要给朋友们分享一下Java编程语言中的变量与常量的区别...
  5. 【笔试/面试】—— 不使用大于、小于、if 语句,实现 max 宏
  6. php颜色十六进制代码,如何通过PHP中的十六进制代码检索颜色的人名
  7. Hadoop2.7.4 HA centos6.8
  8. 在 Windows 下远程桌面连接 Linux - VNC 篇
  9. 从顶会论文看对比学习的应用!
  10. hbase的快速下载
  11. excel下拉框引用另外一个sheet
  12. python 双冒号_python双冒号
  13. stm32程序flash下载和sram运行
  14. 亚马逊多账号注册怎么操作?多账号注册有哪些解决方案?
  15. 喜讯!云效度量能力获信通院先进级评估
  16. Maya用样条线制作面片头发
  17. 《Thinking in Bets》读书分享 - 如何在信息不完全情况下做出更好的决策(1)...
  18. SpringMVC之405错误码
  19. 图解电脑上Firefox浏览器无法打开的解决办法
  20. 语义分割--Dilated Residual Networks

热门文章

  1. 碧桂园出品的机器人,能够代替公司人力吗?
  2. 诸神之眼 Nmap入门
  3. k8s教程(Volume篇)-PV详解
  4. 蓝牙模块通信c语言,求一个蓝牙模块发送数据的例子
  5. java 如何在拦截器重定向,java – 来自登录拦截器的Struts2重定向
  6. SpringApplication.run(MyApplication.class, args)运行流程源码分析
  7. 作为外包,你冤枉了吗?| 程序员有话说
  8. PBA大理石直线电机模组优势
  9. 如何获得ADI公司的技术支持服务
  10. 如何打开 plist 文件