C++primer 第 4 章 表达式 4.7条件运算符 4.8位运算符 4.9 sizeof运算符 4.10逗号运算符 4.11类型转换 4 . 1 2 运算符优先级表

4.7条件运算符

  • 条件运算符(?:)允许我们把简单的if else逻辑嵌入到单个表达式当中,条件运算符按照如下形式使用:
  • cond ? expr1 : expr2;其中cond是判断条件的表达式,而expr1和expr2是两个类型相同或可能转换为某个公共类型的表达式。条件运算符的执行过程是:首先求cond的值,如果条件为真对expr1求值并返回该值,否则对expr2求值并返回该值。举个例子,我们可以使用条件运算符判断成绩是否合格:
  • string finalgrade = (grade<60) ?"fail" : "pass”;
  • 条件部分判断成绩是否小于60。如果小于,表达式的结果是"fail",否则结果是"pass"。有点类似于逻辑与运算符和逻辑或运算符(&&和||),条件运算符只对expr1和expr2中的一个求值。
  • 当条件运算符的两个表达式都是左值或者能转换成同一种左值类型时,运算的结果是左值;否则运算的结果是右值。

嵌套条件运算符

  • 允许在条件运算符的内部嵌套另外一个条件运算符。也就是说,条件表达式可以作为另外一个条件运算符的cond或expr
  • 举个例子,使用一对嵌套的条件运算符可以将成绩分成三档:优秀(highpass)>合格(pass)和不合格(fail):
  • finalgrade=(grade>90)?"highpassn:(grade<60)?“fail":"pass";
  • 第一个条件检查成绩是否在90分以上,如果是,执行符号?后面的表达式,得到"highpass";如果否,执行符号:后面的分支。这个分支本身又是一个条件表达式,它检查成绩是否在60分以下,如果是,得到"fail";否则得到"pass"。
  • 条件运算符满足右结合律,意味着运算对象(一般)按照从右向左的顺序组合。因此在上面的代码中,靠右边的条件运算(比较成绩是否小于60)构成了靠左边的条件运算的:分支。
  • 随着条件运算嵌套层数的增加,代码的可读性急剧下降.因此,条件运算的嵌套最好别超过两到三层

4.8位运算符

  • 位运算符作用于整数类型的运算对象,并把运算对象看成是二进制位的集合。位运算符提供检查和设置二进制位的功能,如17.2节(第640页)将要介绍的,一种名为bitset的标准库类型也可以表示任意大小的二进制位集合,所以位运算符同样能用于bitset类型.

  • 一般来说,如果运算对象是''小整型”,则它的值会被自动提升(参见4.11.1节,第142页)成较大的整数类型。运算对象可以是带符号的,也可以是无符号的。如果运算对象是带符号的且它的值为负,那么位运算符如何处理运算对象的“符号位”依赖于机器。而且,此时的左移操作可能会改变符号位的值,因此是一种未定义的行为。
  • 关于符号位如何处理没有明确的规定,所以强烈建议仅将位运算符用于处理无符号类型。

移位运算符

  • 之前在处理输入和输出操作时,我们已经使用过标准IO库定义的<<运算符和>>运算符的重载版本。这两种运算符的内置含义是对其运算对象执行基于二进制位的移动操作,首先令左侧运算对象的内容按照右侧运算对象的要求移动指定位数,然后将经过移动的(可能还进行了提升)左侧运算对象的拷贝作为求值结果。其中,右侧的运算对象一定不能为负,而且值必须严格小于结果的位数,否则就会产生未定义的行为。二进制位或者向左移(?)或者向右移(?),移出边界之外的位就被舍弃掉了:

  • 左移运算符(<<)在右侧插入值为0的二进制位。右移运算符(>>)的行为则依赖于其左侧运算对象的类型:如果该运算对象是无符号类型,在左侧插入值为0的二进制位:
  • 如果该运算对象是带符号类型,在左侧插入符号位的副本或值为0的二进制位,如何选择要视具体环境而定。

位求反运算符

  • 位求反运算符( ~) 将运算对象逐位求反后生成一个新值,将 1 置为0、将 0 置为1:
  • char类型的运算对象首先提升成int类型,提升时运算对象原来的位保持不变,往高位(highorderposition)添加0即可。因此在本例中,首先将bits提升成int类型,增加24个高位0,随后将提升后的值逐位求反。

位与、位或、位异或运算符

  • 与(&)、或(|)、异或(^)运算符在两个运算对象上逐位执行相应的逻辑操作:

  • 对于位与运算符(&)来说,如果两个运算对象的对应位置都是1则运算结果中该位为1,否则为0。对于位或运算符(|)来说,如果两个运算对象的对应位置至少有一个为1则运算结果中该位为1,否则为0。对于位异或运算符(^)来说,如果两个运算对象的对应位置有且只有一个为1则运算结果中该位为1,否则为0

移位运算符(又叫10运算符)满足左结合律

  • 尽管很多程序员从未直接用过位运算符,但是几乎所有人都用过它们的重载版本来进行10操作。重载运算符的优先级和结合律都与它的内置版本一样,因此即使程序员用不到移位运算符的内置含义,也仍然有必要理解其优先级和结合律。
  • 因为移位运算符满足左结合律,所以表达式

4.9 sizeof运算符

  • sizeof运算符返回一条表达式或一个类型名字所占的字节数。sizeof运算符满足右结合律,其所得的值是一个size_t类型(参见3.5.2节,第 103页)的常量表达式(参 见2.4.4节,第 58页)。运算符的运算对象有两种形式:
  • sizeof (type)
  • sizeof expr

  • 这些例子中最有趣的一个是sizeof *p。首先,因为sizeof满足右结合律并且与*运算符的优先级一样,所以表达式按照从右向左的顺序组合。也就是说,它等价于sizeof(*p)
  • 其次,因为sizeof不会实际求运算对象的值,所以即使p是一个无效(即未初始化)的指针(参见2.3.2节,第47页)也不会有什么影响。在sizeof的运算对象中解引用一个无效指针仍然是一种安全的行为,因为指针实际上并没有被真正使用。
  • sizeof不需要真的解引用指针也能知道它所指对象的类型。新标准允许我们使用作用域运算符来获取类成员的大小。通常情况下只有通过类的对象才能访问到类的成员,但是sizeof运算符无须我们提供一个具体的对象,因为要想知道类成员的大小无须真的获取该成员。
  • sizeof运算符的结果部分地依赖于其作用的类型:
  • 对char或者类型为char的表达式执行sizeof运算,结果得1。
  • 对引用类型执行sizeof运算得到被引用对象所占空间的大小。
  • 对指针执行sizeof运算得到指针本身所占空间的大小。
  • 对解引用指针执行sizeof运算得到指针指向的对象所占空间的大小,指针不需有效。
  • 对数组执行sizeof运算得到整个数组所占空间的大小,等价于对数组中所有的元素各执行一次sizeof运算并将所得结果求和。注意,sizeof运算不会把数组转换成指针来处理。
  • 对string对象或vector对象执行sizeof运算只返回该类型固定部分的大小,不会计算对象中的元素占用了多少空间。
  • 因为执行sizeof运算能得到整个数组的大小,所以可以用数组的大小除以单个元素的大小得到数组中元素的个数:

 

4.10逗号运算符

  • 逗号运算符含有两个运算对象,按照从左向右的顺序依次求值。和逻辑与、逻辑或以及条件运算符一样,逗号运算符也规定了运算对象求值的顺序。
  • 对于逗号运算符来说,首先对左侧的表达式求值,然后将求值结果丢弃掉。逗号运算符真正的结果是右侧表达式的值。如果右侧运算对象是左值,那么最终的求值结果也是左值。
  • 逗号运算符经常被用在for循环当中:

 

4.11类型转换

  • 在C++语言中,某些类型之间有关联。如果两种类型有关联,那么当程序需要其中一种类型的运算对象时,可以用另一种关联类型的对象或值来替代。换句话说,如果两种类
  • 型可以相互转换(conversion),那么它们就是关联的。举个例子,考虑下面这条表达式,它的目的是将ival初始化为6:
  • int ival = 3.541 + 3; / / 编译器可能会警告该运算损失了精度
  • 加法的两个运算对象类型不同:3.541的类型是double,3的类型是int。C++语言不会直接将两个不同类型的值相加,而是先根据类型转换规则设法将运算对象的类型统一后再求值。上述的类型转换是自动执行的,无须程序员的介入,有时甚至不需要程序员了解。因此,它们被称作隐式转换(implicitconversion)。算术类型之间的隐式转换被设计得尽可能避免损失精度。很多时候,如果表达式中既有整数类型的运算对象也有浮点数类型的运算对象,整型会转换成浮点型。在上面的例子中,3转换成double类型,然后执行浮点数加法,所得结果的类型是double。接下来就要完成初始化的任务了。在初始化过程中,因为被初始化的对象的类型无法改变,所以初始值被转换成该对象的类型。仍以这个例子说明,加法运算得到的double类型的结果转换成int类型的值,这个值被用来初始化ival。由double向int转换时忽略掉了小数部分,上面的表达式中,数值6被赋给了ival。

何时发生隐式类型转换

  • 在下面这些情况下,编译器会自动地转换运算对象的类型:
  • 在大多数表达式中,比int类型小的整型值首先提升为较大的整数类型。
  • 在条件中,非布尔值转换成布尔类型。
  • 初始化过程中,初始值转换成变量的类型;在赋值语句中,右侧运算对象转换成左侧运算对象的类型。
  • 如果算术运算或关系运算的运算对象有多种类型,需要转换成同一种类型。
  • 如第6章将要介绍的,函数调用时也会发生类型转换。

4.11.1算术转换

  • 算术转换(arithmeticconversion)的含义是把一种算术类型转换成另外一种算术类型,这一点在2.1.2节(第32页)中已有介绍。算术转换的规则定义了一套类型转换的层次,其中运算符的运算对象将转换成最宽的类型。例如,如果一个运算对象的类型是long double,那么不论另外一个运算对象的类型是什么都会转换成long double。还有一种更普遍的情况,当表达式中既有浮点类型也有整数类型时,整数值将转换成相应的浮点类型。

整型提升

  • 整型提升 ,负责把小整数类型转换成较大的整数类型。对于bool、char、signedchar、unsignedchar、short和unsignedshort等类型来说,只要它们所有可能的值都能存在int里,它们就会提升成int类型;否则,提升成unsigned int类型。就如我们所熟知的,布尔值false提升成0、true提升成1。较大的char类型(wchar_t、charl6_t、char32_t)提升成int、unsignedint、long、unsigned long、long long和unsigned long long中最小的一种类型,前提是转换后的类型要能容纳原类型所有可能的值。

无符号类型的运算对象

  • 如果某个运算符的运算对象类型不一致,这些运算对象将转换成同一种类型。但是如果某个运算对象的类型是无符号类型,那么转换的结果就要依赖于机器中各个整数类型的相对大小了。像往常一样,首先执行整型提升。如果结果的类型匹配,无须进行进一步的转换。如果两个(提升后的)运算对象的类型要么都是带符号的、要么都是无符号的,则小类型的运算对象转换成较大的类型。
  • 如果一个运算对象是无符号类型、另外一个运算对象是带符号类型,而且其中的无符号类型不小于带符号类型,那么带符号的运算对象转换成无符号的。例如,假设两个类型分别是unsigned int和int,则int类型的运算对象转换成unsigned int类型。需要注意的是,如果int型的值恰好为负值,其结果将以2.1.2节(第32页)介绍的方法转换,并带来该节描述的所有副作用。
  • 剩下的一种情况是带符号类型大于无符号类型,此时转换的结果依赖于机器。如果无符号类型的所有值都能存在该带符号类型中,则无符号类型的运算对象转换成带符号类型。如果不能,那么带符号类型的运算对象转换成无符号类型。例如,如果两个运算对象的类型分别是long和unsigned int,并且int和long的大小相同,则long类型的运算对象转换成unsignedint类型;如果long类型占用的空间比int更多,则unsigned int类型的运算对象转换成long类型。

理解算术转换

  • 要想理解算术转换,办法之一就是研究大量的例子:

  • 在第一个加法运算中,小写字母,a,是char型的字符常量,它其实能表示一个数字值(参见2.1.1节,第30页)。到底这个数字值是多少完全依赖于机器上的字符集,在我们的环境中,a,对应的数字值是97。当把,a,和一个longdouble类型的数相加时,char类型的值首先提升成int类型,然后int类型的值再转换成longdouble类型。最终我们把这个转换后的值与那个字面值相加。最后的两个含有无符号类型值的表达式也比较有趣,它们的结果依赖于机器

4.11.2其他隐式类型转换

  • 除了算术转换之外还有几种隐式类型转换,包括如下几种。
  • 数组转换成指针:在大多数用到数组的表达式中,数组自动转换成指向数组首元素的指针:

  • 当数组被用作decltype关键字的参数,或者作为取地址符(&)、sizeof及typeid(第19.2.2节,732页将介绍)等运算符的运算对象时,上述转换不会发生。同样的,如果用一个引用来初始化数组(参见3.5.1节,第102页),上述转换也不会发生。我们将在6.7节(第221页)看到,当在表达式中使用函数类型时会发生类似的指针转换。
  • 指针的转换:C++还规定了几种其他的指针转换方式,包括常量整数值0或者字面值nullptr能转换成任意指针类型;指向任意非常量的指针能转换成void*;指向任意对象的指针能转换成const void*.15.2.2节(第530页)将要介绍,在有继承关系的型间还有另外一种指针转换的方式。

4.11.3显式转换

  • 有时我们希望显式地将对象强制转换成另外一种类型。例如,如果想在下面的代码中执行浮点数除法:
  • int i,j;   double   slope  = i/j;
  • 就要使用某种方法将i和/或j显式地转换成double,这种方法称作强制类型转换(cast)
  • 然有时不得不使用强制类型转换,但这种方法本质上是非常危险的

命名的强制类型转换

  • 一个命名的强制类型转换具有如下形式:
  • cast-name<type> (expression); 其中,type是转换的目标类型而expression是要转换的值。如果是引用类型 ,则结果是左值 。 cast-name是static cast、dynamic cast、const cast和
    reinterpret_cast中的一种。dynamic_cast支持运行时类型识别,我们将在19.2节(第730页)其做更详细的介绍。cast-name指定了执行的是哪种转换。

reinterpret__cast

  • reinterpret_cast通常为运算对象的位模式提供较低层次上的重新解释。举个例子,假设有如下的转换

  • reinterpret_cast本质上依赖于机器。要想安全地使用reinterpret_cast必须对涉及的类型和编译器实现转换的过程都非常了解;

 4 . 1 2 运算符优先级表

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Git 之 git tag标签使用

目录一、简介二、本地tag操作1、创建tag标签&#xff08;1&#xff09;创建轻量标签&#xff08;2&#xff09;创建附注标签2、查看tag标签&#xff08;1&#xff09;查看标签列表&#xff08;2&#xff09;查看标签提交信息&#xff08;3&#xff09;在提交历史中查看标签3、删…

codeforces 110A-C语言解题报告

110A题目网址 题目解析 1.输入一个数字,如果数字中包含的4,7的数量是4或7的倍数,则输出YES,否则输出NO 举例: 输入: 40047 输出: NO 2.注意点: 1)由于数字很长,所以使用long long int类型,使用scanf("%lld",&n)接收输入 2)整型转字符串,使用sprintf(字符串,“…

C++primer 第 5 章语句 5.2语句作用域 5.3条件语句 5 . 4 迭代语句 5.5跳转语句 5.6 try语句块和异常处理

5 . 1 简单语句 C语言中的大多数语句都以分号结束&#xff0c;一个表达式&#xff0c;比如ival 5 , 末尾加上分号就变成了表达式语句(expression statement)。表达式语句的作用是执行表达式并丢弃掉求值结果&#xff1a;ival 5&#xff1b; // 一条没什么实际用处的表达式语…

英语口语-文章朗读Week9Thursday

英语文章 Everyone has his or her own dreams. Some people wants to be millionaires so they can give many generous donations later; some people want to be scientists so they can bring many conveniences to the world; some people only want to be bus-drivers s…

操作系统 内存管理相关知识

cpu执行程序的基本过程 译码器 输入为n管脚&#xff0c;输出为2^n根管脚&#xff0c;编号为从0到2^(n-1)&#xff0c;用少的输入端控制更多的输出端最常用的是三八译码器AD(Address bus)地址总线: 选中一行数据每一行 8bit 组成8吧B cpu输入端32根线&#xff0c;输出端就可以控…

2000年考研英语阅读理解文章四

文章详细解析网址 注意点 1.注意But,however等表示观点看法转折的词语 2.全篇都在提及moral decline 道德下降,最后一段写that may have more to do with life-style所以造成现象的原因应该是life-style.(主要) 前面都是在分析,最后一段点名原因 知识点 ----单词 envy n/v…

Chrome浏览器必装插件!尤其程序猿!

Chrome 浏览器有一个好处&#xff0c;就是插件极其丰富&#xff0c;只有你想不到的&#xff0c;没有你找不到的&#xff0c;这恐怕是 Chrome 浏览器被众多爱好者钟爱的原因吧。 言归正传&#xff0c;今天来给大家推荐 10 款我自己珍藏的 Chrome 浏览器插件。 1、crxMouse Ch…

codeforces 160A-C语言解题报告

160A题目网址 题目解析 1.输入硬币的个数,分配硬币,使拿最小的硬币数比剩下的硬币金额大 举例: 输入: 2 3 3 输出 2 2.注意点: 1)接收整型数组时要使用&,因为只有字符数组是使用指针传递首地址的 scanf("%d",&a[i]); 2)使用冒泡排序,将数组从大到小排序…

英语口语-文章朗读Week10 Monday

英语文章 Here are some valuable suggestions which may assist you in landing good job First, make your resume clear and associate it with the position you are applying for. Try to add details like your temporary jobs at college or your former jobs Second, …

论文遇到的格式问题和修正方式

word空格出现小圆点怎么办论文参考文献批量改为上角标&#xff0c;简单好用&#xff01;&#xff01;&#xff01;字数统计网站word封面下划线怎么对齐&#xff08;非常简单彻底解决&#xff09;

codeforces 41A-C语言解题报告

41A题目网址 题目解析 1.输入一个字符串,如果第二行是倒序输入这个字符串的,就输出YES,否则输出NO 举例: 输入: abb aba 输出: NO 2.倒序输出时,使用int jstrlen(t)-1;,因为strlen()是计算字符个数,而字符串是从0开始,最后一位是字符串长度减一 3.在接收第二个字符串输入时…

Linux查看文件的首个字母 文件属性字段

-rw-r–r– 1 root root 762 07-29 18:19 exit文件属性字段总共有10个字母组成&#xff1b;第一个字符代表文件的类型。 文件属性字段 字母“-”表示该文件是一个普通文件字母“d”表示该文件是一个目录&#xff0c;字母”d”&#xff0c;是dirtectory(目录)的缩写&#xff1b…

英语口语-文章朗读Week10 Wednesday

英语文章 Everyone needs sleep for survival, but how much? It is said that eight hours of sleep is fundamental to a healthy person. But today, many people are sacrificing their sleep time。 Modern people have so many alternatives: cell phones, PCs, TVs, g…

嵌入式Linux多任务编程 进程 管道 命名管道

进程 进程是一个可并发执行的具有独立功能的程序关于某个数据集合的一次执行过程&#xff0c;也是操作系统执行资源分配和保护的基本单位。程序的一次执行就是一个进程一个程序可以派生多个进程多个不同程序运行的时候&#xff0c;也会有多个相对应的进程与其相互对应进程是动…

2000年考研英语阅读理解文章五

文章详细解析网址 知识点 ----单词 vitality n生命力 hypocritical adj伪善的 pushing adj有进取心的 acquisitive adj渴望获得的,贪得无厌的 confess v供认,坦白 vulgar adj粗俗的 spectacle n场面,奇观 participatory adj供分享的 democracy n民主,民主制,民主国家 stir v搅…

英语口语-文章朗读Week10 Thursday

英语文章 There are many customs and traditions in Chinese civilization. Here, we will talk about the development of the way people greet each other: In ancient times, people had to kneel to those who were superior to them. This custom remained until the …

Linux进程之间通信 信号

2) SIGINT 程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出&#xff0c;用于通知前台进程组终止进程。 3) SIGQUIT 和SIGINT类似, 但由QUIT字符(通常是Ctrl-\)来控制. 进程在因收到SIGQUIT退出时会产生core文件, 在这个意义上类似于一个程序错误信号。 15)…

c++面向对象高级编程 学习一 不带指针的类

复数类 complex 是一个不带指针的类&#xff0c;其声明如下&#xff1a; class complex { public: complex(double r0,double i0):re(r),im(i){} complex& operator (const complex&); double real()const{return re;} double imag()const{return im;}private: double…