(转载)你好,C++(18) 到底要不要买这个西瓜?4.1.6 操作符之间的优先顺序

你好,C++(18) 到底要不要买这个西瓜?4.1.6 操作符之间的优先顺序

4.1.6 操作符之间的优先顺序

在表达一些比较复杂的条件判断时,在同一个表达式中,有时可能会存在多个操作符。比如,我们在判断要不要买某个西瓜时,不仅要判断它的总价(单价8.2元/斤,一共10.3斤)是否小于100块钱(因为兜里只有这么多钱),同时还要判断这个西瓜是否有坏掉的地方。要表达这个复杂的条件判断,我们不得不把前面学过的算术操作符、关系操作符和逻辑操作符全都派上场:

bool bBad = false;   // 是否有坏掉的地方
float fPrice = 8.2;  // 单价
float fWeight = 10.3;    // 重量
// 判断总价是否小于100且是否坏掉
if(fPrice * fWeight < 100 && !bBad)
{
    cout<<"买西瓜"<<endl;
}
else
{
    cout<<"算了,不买了"<<endl;
}

在“fPrice * fWeight < 100 && !bBad”这个表达式中,有算术操作符“*”,有关系操作符“<”,同时也还有逻辑操作符“!”和“&&”。那么,这么多操作符在同一个表达式中,到底该从哪一个操作开始呢?这个表达式的最终结果又是什么呢?

要想搞清楚一个表达式是按照什么顺序计算的,就得先搞清楚各个操作符之间的计算优先级。按照正确的计算顺序进行计算,才可以得出正确的结果。在C++中,各个操作符的优先级如表4-1所示。

表4-1  操作符的优先级


级别


操  作  符


说    明


1


( )


括号是所有操作符中的领导,具有最高的优先级。如果括号内部还有括号,内部括号的优先级更高


2


!、+(正号)、-(负号)、++、--


它们都是一元操作符,往往是对操作数进行计算得到结果后继续参与下一个计算

注意,这里的+、-指的是改变数值正负属性的符号,而不是加减操作的符号


3


*、/、%


乘、除、取余运算


4


+、-


加、减运算


5


>、>=、<、<=、==、!=


关系运算


6


&&


逻辑与运算,它会首先计算其左侧表达式的值,当其值为true时,才会继续计算右侧表达式的值,最后计算两个值的逻辑与


7


||


逻辑或运算,它同样会首先计算其左侧表达式的值,若其值为false,则继续计算右侧表达式的值,最后计算两个值的逻辑或


8


=、+=、*=、/=、%=


赋值操作

表达式的计算顺序规则是:总是优先计算优先级较高的操作符;同一优先级的操作符,则按照从左到右的顺序进行计算;如果有特殊规则的操作符(比如逻辑与“&&”),则按照特殊规则进行计算。在清楚了各操作符的优先级及表达式的计算规则后,那就可以计算上面这个复杂表达式的结果了。在这个表达式中,有一个拥有特殊规则的操作符“&&”,按照它的计算规则,这个表达式会首先计算其左侧表达式的值:

fPrice * fWeight < 100  // 首先得到计算的左侧表达式

在这个表达式中,没有特殊规则的操作符,那就按照操作符的优先级进行计算。其中,优先级最高的是计算总价的乘法算术操作符“*”,对其进行计算后得到一个中间结果:

84.46 < 100   // fPrice*fWeight的结果是84.46

这个中间结果表达式只有一个操作符,直接计算得到其结果值为true。按照“&&”操作符的计算规则,如果左侧表达式的值为true,则继续计算其右侧表达式的值。所以,接下来要计算的表达式变为:

true && !bBad     // 左侧表达式计算完成后的中间结果

在“&&”的右侧只有一个操作符“!”,直接计算得到的中间结果是:

true && true

现在,剩下唯一的逻辑与操作符“&&”,最终结果一目了然,对两个true值进行逻辑与运算,表达式的最终结果是true。计算机在对表达式进行计算时,是按照各个操作符的优先级确定的计算顺序进行的。反过来,这也就要求我们在设计表达式的时候,也同样必须遵守操作符的优先顺序,按照这个顺序来设计表达式。否则,实际的计算顺序跟我们设想的计算顺序不同,得到的计算结果自然也就跟我们的设想大相径庭了。从这个意义上讲,熟悉和掌握操作符的优先级十分必要。

最佳实践:合理使用括号标示表达式的计算顺序

从上面这个例子我们可以看到,过于复杂的表达式计算起来非常麻烦。虽然表达式是由计算机负责计算,我们不用担心计算机怕麻烦。但是,表达式却是由程序员进行设计,并且也是要提供给他人阅读的。设计过于复杂的表达式很容易出错,且代码的可读性非常差。所以我们应当尽量避免在同一表达式中混合使用多个操作符,尽量保持表达式的短小精悍。必要的时候,可以将复杂的表达式拆分成多个较小的表达式分别计算得到中间结果,最后再将中间结果组合起来得到最终结果。例如,我们可以把上面的复杂表达式拆分成两个较小的表达式,分别判断是否有坏掉的地方以及总价是否小于100块,然后再将这两个中间结果进行“与”运算,得到最终结果:

// 将复杂表达式拆分成两个较小的表达式
bool bFresh = !bBad;    // 表示是否新鲜
float fTotal = fPrice * fWeight; // 计算总价
bool bMoney = fTotal < 100;  // 判断总价是否小于100块
// 对中间结果进行比较
if( bFresh && bMoney)
// …

经过这样的拆分,每个表达式的计算都清楚明了,减少了出错的可能,可读性也得到了提升。但是它同时也带来一个不便之处,那就是代码变的过于繁琐。既想得到拆分表达式带来的清楚明了的好处,又想避免代码繁琐的不便,那就只有使用“()”了。

“()”的优先级是所有操作符中最高的,使用它,可以人为地按照设计者的意图标示表达式中的计算顺序。比如,可以改写上面的表达式,用括号来表达我们希望的计算顺序,让其表达的意义更加清晰:

// …
if(((fPrice * fWeight) < 100) && (!bBad))
// …

使用括号后,整个表达式的计算顺序变得一目了然:按照括号确定的计算顺序,首先计算最里层的(fPrice * fWeight) 得到中间结果84.46,然后计算(84.46 < 100)得到中间结果true,接着计算(!bBad)得到中间结果true,最后计算“true && true”得到最终结果true。使用括号后,计算顺序跟默认顺序相同,但是却增加了代码的可读性,让我们对计算顺序一目了然,同时也避免了让代码变得过于繁琐。另外,在某些特殊情况下需要改变表达式的默认计算顺序时,括号成为一种必须。

总结起来,使用“()”后,我们想让表达式按照什么顺序计算就按照什么顺序计算,妈妈再也不用担心我记不住各个操作符的优先级。

4.1.7  将表达式组织成语句

学习C++编程,实际上也就是学习如何使用这门特殊的语言来描述和表达现实世界,就如同我们学习英语是为了用它来描述和表达现实世界一样。在前面的章节中,我们学习了操作符,学习了由操作符连接操作数而构成的各种表达式,而这些只能算是这门语言中的“短语”,它们可以表达一定的意义,但却是不完整的:

// 短语式的表达式
a        // 一个单独的变量,什么都不做
3 + 2    // 用算术操作符“+”计算3和2的和

这些表达式可以被执行,但它们并不改变程序的状态,也没有计算结果保留下来,所以没有任何实际的意义。就像在英语中我们需要给短语加上主谓宾才能构成一个完整的句子一样,在C++中,我们也同样需要把一些表达零散意义的表达式组合起来,最后再加一个英文分号表示结束,以此来形成一个语句,用以完成某个相对独立而完整的功能。例如,把上面两个表达式通过赋值操作符组合起来,就形成了一条完整的赋值语句:

// 赋值语句
a = 3 + 2;

形成语句后,它表达了一个完整的意义:用算术操作符“+”计算3和2的和,然后将其赋值给变量a。

在C++中,语句和表达式并没有严格的区分。很多时候,一个表达式加上一个分号就可以直接形成一条语句。语句强调它所完成的功能,而表达式关注它所描述的运算和最终的结果。在此之前,我们已经接触过两种最常见的语句类型:变量定义语句和赋值语句。

知道更多:使用“{}”表示的语句块

当连续的多条语句属于同一个控制结构时,可以用一对花括号“{}”将这些语句括起来,从而形成一个语句块,共同表达一个相对独立的意义。在使用上,语句块与单独的语句并无太大区别,但是它的意义在于,它可以将多条语句打包成一个语句块,从而可以在for循环等控制结构中执行多条语句。例如,在for循环结构中,我们可以这样来统计从1到100间所有整数的和:

int nTotal = 0;

for(int i = 1; i <= 100; ++i)
 nTotal += i;

这个统计只需要一条语句就可以完成,自然可以把这条语句直接放在for循环结构之后完成,可是如果我们只需要统计这个区间中所有偶数的和,那么就需要加上条件判断,这就不是单独一条语句可以完成的了。我们必须用“{}”将所有判断偶数、统计偶数的语句打包成一个语句块,然后放在for循环结构之后才能完成统计:

for(int i = 1; i <= 100; ++i)
 { // for循环语句块开始
        if(0 == i%2) // 判断语句
            nTotal += i; // 统计语句
} // for循环语句块结束

除了打包语句之外,语句块的另外一个意义是,它代表了C++中的作用域的起讫位置。关于作用域的具体介绍可以参考后继的7.3.3小节。

原文地址:http://www.cnblogs.com/nihaoCPP/p/4085033.html

时间: 2024-10-10 09:08:40

(转载)你好,C++(18) 到底要不要买这个西瓜?4.1.6 操作符之间的优先顺序的相关文章

你好,C++(18) 到底要不要买这个西瓜?4.1.6 操作符之间的优先顺序

4.1.6 操作符之间的优先顺序 在表达一些比较复杂的条件判断时,在同一个表达式中,有时可能会存在多个操作符.比如,我们在判断要不要买某个西瓜时,不仅要判断它的总价(单价8.2元/斤,一共10.3斤)是否小于100块钱(因为兜里只有这么多钱),同时还要判断这个西瓜是否有坏掉的地方.要表达这个复杂的条件判断,我们不得不把前面学过的算术操作符.关系操作符和逻辑操作符全都派上场: bool bBad = false; // 是否有坏掉的地方 float fPrice = 8.2; // 单价 floa

[转载]你刚才在淘宝上买了一件东西

你发现快要过年了,于是想给你的女朋友买一件毛衣,你打开了www.taobao.com.这时你的浏览器首先查询DNS服务器,将www.taobao.com转换成ip地址.不过首先你会发现,你在不同的地区或者不同的网络(电信.联通.移动)的情况下,转换后的ip地址很可能是不一样的,这首先涉及到负载均衡的第一步,通过DNS解析域名时将你的访问分配到不同的入口,同时尽可能保证你所访问的入口是所有入口中可能较快的一个(这和后文的CDN不一样). 你通过这个入口成功的访问了www.taobao.com的实际

(转载)你好,C++(5)如何输出数据到屏幕、从屏幕输入数据与读写文件?

你好,C++(5)如何输出数据到屏幕.从屏幕输入数据与读写文件? 2.2  基本输入/输出流 听过HelloWorld.exe的自我介绍之后,大家已经知道了一个C++程序的任务就是描述数据和处理数据.这两大任务的对象都是数据,可现在的问题是,数据不可能无中生有地产生,C++程序也不可能凭空创造出来数据.那么,C++程序中的数据又从何而来呢? 在现实世界中,国与国之间的交流是通过外交官来完成的.在C++世界中,也有负责应用程序跟外界进行数据交流的外交官,它们的名字就是基本输入/输出流对象(iost

(转载)你好,C++(4)2.1.3 我的父亲母亲:编译器和链接器 2.1.4 C++程序执行背后的故事

你好,C++(4)2.1.3 我的父亲母亲:编译器和链接器 2.1.4 C++程序执行背后的故事 2.1.3  我的父亲母亲:编译器和链接器 从表面上看,我是由Visual Studio创建的,而实际上,真正负责编译源代码创建生成可执行程序HelloWorld.exe的却是Visual Studio中集成的C++编译器cl.exe和链接器link.exe.他们二老,才是我的亲生爹妈. 为了便于人们的编写.阅读和维护,我们的源文件是使用C++这种人们可以理解的高级程序设计语言编写的.然而,计算机却

[转载]在SQL Server 中,如何实现DBF文件和SQL Server表之间的导入或者导出?

原来使用SQL Server 2000数据库,通过DTS工具很方便地在SQL Server和DBF文件之间进行数据的导入和导出,现在安装了SQL Server2005之后,发现其提供的“SQL Server导入导出向导”中的数据源没有原来的丰富,缺少对DBF文件的支持. 1.右击数据库,选择“任务”>“导入数据”,打开“SQL Server导入和导出向导”对话框.2.在“数据源”中选择Microsoft OLE DB Provider for Visual FoxPro,单击“属性”按钮,打开“

超级详细的iptable教程文档

Iptabels是与Linux内核集成的包过滤防火墙系统,几乎所有的linux发行版本都会包含Iptables的功能.如果 Linux 系统连接到因特网或 LAN.服务器或连接 LAN 和因特网的代理服务器, 则Iptables有利于在 Linux 系统上更好地控制 IP 信息包过滤和防火墙配置. netfilter/iptables过滤防火墙系统是一种功能强大的工具,可用于添加.编辑和除去规则,这些规则是在做信息包过滤决定时,防火墙所遵循和组成的规则.这些规则存储在专用的信 息包过滤表中,而这

我的第一本C++书,目录

共分三篇十三章.这是总目录,细分到节: 1 /* 2 3 我的第一本C++书(游历C++世界的地图) 4 5 第1篇 叩开c++世界的大门 6 7 8 第1章 c++世界地图 9 1.1 c++是什么 10 1.2 c++的前世今生 11 1.2.1 从b到c 12 1.2.2 从c到c++ 13 1.2.3 从c++到.net framework的cli 14 1.2.4 最新标准c++0x让c++重新焕发活力 15 1.2.5 c++和c#不得不说的那点事儿 16 1.2.6 c++世界的五

Linux之Iptables总结及应用

Linux之Iptables总结及应用 一.防火墙.Iptables简介 1.防火墙是用于实现Linux下访问控制的功能的,它分为硬件的或者软件的防火墙两种.无论是在哪个网络中,防火墙工作的地方一定是在网络的边缘.而我们的任务就是需要去定义到底防火墙如何工作,这就是防火墙的策略,规则,以达到让它对出入网络的IP.数据进行检测.常见的有三.四层的防火墙,叫网络层的防火墙(这层对源地址和目标地址进行检测),还有7层防火墙,其实是代理层的网关(对源端口或者目标端口,源地址或者目标地址进行检查). 2.

详解iptables

Firewalls(防火墙):         工作在网络边缘(主机边缘),对进出网络数据包基于一定的规则检查,并在匹配某规则时由规则定义的处理进行处理的一组功能的组件. 防火墙类型:根据工作的层次的不同来划分,常见的防火墙工作在OSI第三层,即网络层防火墙,工作在OSI第七层的称为应用层防火墙,或者代理服务器(代理网关). 网络层防火墙又称包过滤防火墙,在网络层对数据包进行选择,选择的依据是系统内设置的过滤逻辑,被称为访问控制列表(ACL),通过检查数据流中每个数据的源地址,目的地址,所用端口