收藏 分享(赏)

c++_运算符的优先级和结合性.doc

上传人:11xg27ws 文档编号:6331460 上传时间:2019-04-07 格式:DOC 页数:10 大小:75.50KB
下载 相关 举报
c++_运算符的优先级和结合性.doc_第1页
第1页 / 共10页
c++_运算符的优先级和结合性.doc_第2页
第2页 / 共10页
c++_运算符的优先级和结合性.doc_第3页
第3页 / 共10页
c++_运算符的优先级和结合性.doc_第4页
第4页 / 共10页
c++_运算符的优先级和结合性.doc_第5页
第5页 / 共10页
点击查看更多>>
资源描述

1、c/c+ 运算符的优先级和结合性 ZZ 2010-05-18 15:29PrecedenceOperator Description ExampleAssociativity1()-.:+-Grouping operatorArray accessMember access from a pointerMember access from an objectScoping operatorPost-incrementPost-decrement(a + b) / 4;array4 = 2;ptr-age = 34;obj.age = 34;Class:age = 2;for( i = 0; i

2、 0; i- ) .left to right2!+-+*for( i = 0; i 0; -i ) .int i = -1;int i = +1;data = *ptr;address = int i = (int) floatNum;int size = sizeof(floatNum);right to left3 -*.*Member pointer selectorMember pointer selectorptr-*var = 24;obj.*var = 24;left to right4*/%MultiplicationDivisionModulusint i = 2 * 4;

3、float f = 10 / 3;int rem = 4 % 3;left to right5 +- AdditionSubtraction int i = 2 + 3;int i = 5 - 1; left to right6 Bitwise shift leftBitwise shift rightint flags = 33 1;left to right7 =Comparison less-than-or-equal-toComparison greater-thanComparison geater-than-or-equal-toif( i 42 ) .if( i = 42 ) .

4、right8 =!=Comparison equal-toComparison not-equal-toif( i = 42 ) .if( i != 42 ) .left to right9 left to right10 Bitwise exclusive OR flags = flags 42; left to right11 | Bitwise inclusive (normal) OR flags = flags | 42; left to right12 right to left15=+=-=*=/=%=a += 3;b -= 4;a *= 5;a /= 2;a %= 3;flag

5、s flags = new_flags;flags |= new_flags;flags = 2;right to left16 , Sequential evaluation operatorfor( i = 0, j = 0; i , +, -其中的自增(+)和自减()都是后缀运算符。2. 第二组的成员是剩下来所有的一元运算符,它们分别是:+, -, +, -, , !, *, 规律二、按照运算符的作用来区分,级别最高的是那些不是严格意义上的运算符,次之是算术运算符,位移运算符,关系运算符,位运算符,逻辑运算符,赋值运算符。此外还有两特别的地方需要注意:一、同为关系运算符,但=和!=的级别

6、低于其它四个;二、第 2组与第 13组的操作符是右结合的,其它的都为左结合;通过分类我们大大减少了需要记忆的内容,遇到使用操作符的时候,我们只需想想它们是什么类型的运算符就可以确定它们之间的相对优先级,从而避免一些不必要的错误。=提起运算符的优先级,很多了解 C+的过来人都会想:这有什么难的?不就是谁的优先级高就算谁么。确实如此,运算符的优先级不是一个大问题,但对于一个初学者来说,却经常容易在上面迷糊与犯错。而对于一个了解 C+的人来说,我相信也会偶尔在上面摔倒,不信就继续往下读。“优先级高的先运算”带来的困惑C+中运算符的优先级有一张表,表里把运算符进行了分类,这张表是不需要死记硬背的,只要

7、有个大致的轮廓就 OK了。例如应该记住最低优先级是逗号运算符,其次是赋值运算符,再其次是三目运算符。而关系运算符的优先级高于逻辑运算符(不包括逻辑非运算),算术运算符的优先级高于关系运算符,象+和的优先级比前面几个都高,但最高的要属()了。知道这些后,你的脑海里一定有一条准则了:优先级高的先运算。那么下面看一个例子:int x=1,y=0;!x上面的语句中出现了!、加括号。此语句有三个运算符:=、? :,应该怎样加括号呢?第一种方案:c=(ab)?a:b);第二种方案:c=(a(b?a:b);第三种方案:(c=a)(b?a:b);应该是那一种呢?按照运算符优先级的高低顺序,优先级高于=,所以不

8、可能把(c=a)括起来。而优先级高于? :运算符。所以也不可能把(b?a:b)括起来。因此,第一种答案正确。下面再看一个类似的例子:int i=8,j=4,k;k=ij?+i:+j;猛然一看,有些人上来可能就要计算+i 和+j 了。这里不妨先加括号看看。从左至右看,的优先级高于=而且又高于? :,所以有 k=(ij)?+i:+j,再继续向右看,由于+高于? :,所以 k=(ij)?(+i):(+j),这样相当于 k=A?B:C,先算 A的值,若为真,则值为 B,即算一下+i,若为假,则值为 C,即算一下+j。整个语句执行完后,k 的值为 5,i 的值为8,j 的值为 5。 =每个操作符拥有某一

9、级别的优先级,同时也拥有左结合性或右结合性。优先级决定一个不含括号的表达式中操作数之间的“紧密”程度。例如,在表达式 a*b+c中,乘法运算的优先级高于加法运算符的优先级,所以先执行乘法 a*b,而不是加法 b+c。但是,许多操作符的优先级都是相同的。这时,操作符的结合性就开始发挥作用了。在表达式中如果有几个优先级相同的操作符,结合性就起仲裁的作用,由它决定哪个操作符先执行。像下面这个表达式:int a,b=1,c=2;a=b=c;我们发现,这个表达式只有赋值符,这样优秀级就无法帮助我们决定哪个操作先执行,是先执行 b=c呢?还是先执行 a=b。如果按前者,a=结果为 2,如果按后者,a 的结

10、果为 1。所以的赋值符(包括复合赋值)都具有右结合性,就是说在表达式中最右边的操作最先执行,然后从右到左依次执行。这样,c 先赋值给 b,然后 b在赋值给 a,最终 a的值是 2.类似地,具有左结合性的操作符(如位操作符“ n = m+m+;最近有位不相识的朋友发 email给我,问为什么在某个 C+系统里,下面表达式打印出两个 4,而不是 4和 5:a = 4; cout a+ a;C+ 不是规定 操作左结合吗?是 C+ 书上写错了,还是这个系统的实现有问题?要弄清这些,需要理解的一个问题是:如果程序里某处修改了一个变量(通过赋值、增量/减量操作等),什么时候从该变量能够取到新值?有人可能说

11、,“这算什么问题!我修改了变量,再从这个变量取值,取到的当然是修改后的值!”其实事情并不这么简单。C/C+ 语言是“基于表达式的语言”,所有计算(包括赋值)都在表达式里完成。“x = 1;”就是表达式“x = 1”后加表示语句结束的分号。要弄清程序的意义,首先要理解表达式的意义,也就是:1)表达式所确定的计算过程;2)它对环境(可以把环境看作当时可用的所有变量)的影响。如果一个表达式(或子表达式)只计算出值而不改变环境,我们就说它是引用透明的,这种表达式早算晚算对其他计算没有影响(不改变计算的环境。当然,它的值可能受到其他计算的影响)。如果一个表达式不仅算出一个值,还修改了环境,就说这个表达式

12、有副作用(因为它多做了额外的事)。a+ 就是有副作用的表达式。这些说法也适用于其他语言里的类似问题。现在问题变成:如果 C/C+ 程序里的某个表达式(部分)有副作用,这种副作用何时才能实际体现到使用中?为使问题更清楚,我们假定程序里有代码片段“.ai+ . aj .”,假定当时 i与 j的值恰好相等(ai 和 aj 正好引用同一数组元素);假定 ai+ 确实在 aj 之前计算;再假定其间没有其他修改 ai 的动作。在这些假定下,ai+ 对 ai 的修改能反映到 aj 的求值中吗?注意:由于 i 与 j 相等的问题无法静态判定,在目标代码里,这两个数组元素访问(对内存的访问)必然通过两段独立代码

13、完成。现代计算机的计算都在寄存器里做,问题现在变成:在取 aj 值的代码执行之前,ai 更新的值是否已经被(从寄存器)保存到内存?如果了解语言在这方面的规定,这个问题的答案就清楚了。程序语言通常都规定了执行中变量修改的最晚实现时刻(称为顺序点、序点或执行点)。程序执行中存在一系列顺序点(时刻),语言保证一旦执行到达一个顺序点,在此之前发生的所有修改(副作用)都必须实现(必须反应到随后对同一存储位置的访问中),在此之后的所有修改都还没有发生。在顺序点之间则没有任何保证。对 C/C+ 语言这类允许表达式有副作用的语言,顺序点的概念特别重要。现在上面问题的回答已经很清楚了:如果在 ai+ 和 aj

14、之间存在一个顺序点,那么就能保证 aj 将取得修改之后的值;否则就不能保证。C/C+语言定义(语言的参考手册)明确定义了顺序点的概念。顺序点位于:1. 每个完整表达式结束时。完整表达式包括变量初始化表达式,表达式语句,return 语句的表达式,以及条件、循环和 switch语句的控制表达式(for 头部有三个控制表达式);2. 运算符 n = m+ +m+;正确回答是:不知道!语言没有规定它应该算出什么,结果完全依赖具体系统在具体上下文中的具体处理。其中牵涉到运算对象的求值顺序和变量修改的实现时刻问题。对于:cout a+ a;我们知道它是(cout.operator (a+).operat

15、or (a);的简写。先看外层函数调用,这里需要算出所用函数(由加下划线的一段得到),还需要计算 a的值。语言没有规定哪个先算。如果真的先算函数,这一计算中出现了另一次函数调用,在被调函数体执行前有一个顺序点,那时 a+的副作用就会实现。如果是先算参数,求出 a的值 4,而后计算函数时的副作用当然不会改变它(这种情况下输出两个 4)。当然,这些只是假设,实际应该说的是:这种东西根本不该写,讨论其效果没有意义。有人可能说,为什么人们设计 C/C+时不把顺序规定清楚,免去这些麻烦?C/C+ 语言的做法完全是有意而为,其目的就是允许编译器采用任何求值顺序,使编译器在优化中可以根据需要调整实现表达式求

16、值的指令序列,以得到效率更高的代码。像 Java那样严格规定表达式的求值顺序和效果,不仅限制了语言的实现方式,还要求更频繁的内存访问(以实现副作用),这些可能带来可观的效率损失。应该说,在这个问题上,C/C+和 Java的选择都贯彻了它们各自的设计原则,各有所获(C/C+ 潜在的效率,Java 更清晰的程序行为),当然也都有所失。还应该指出,大部分程序设计语言实际上都采用了类似 C/C+的规定。讨论了这么多,应该得到什么结论呢?C/C+ 语言的规定告诉我们,任何依赖于特定计算顺序、依赖于在顺序点之间实现修改效果的表达式,其结果都没有保证。程序设计中应该贯彻的规则是:如果在任何“完整表达式”(形

17、成一段由顺序点结束的计算)里存在对同一“变量”的多个引用,那么表达式里就不应该出现对这一“变量”的副作用。否则就不能保证得到预期结果。注意:这里的问题不是在某个系统里试一试的问题,因为我们不可能试验所有可能的表达式组合形式以及所有可能的上下文。这里讨论的是语言,而不是某个实现。总而言之,绝不要写这种表达式,否则我们或早或晚会某种环境中遇到麻烦。后记:去年参加一个学术会议,看到有同行写文章讨论某个 C系统里表达式究竟按什么顺序求值,并总结出一些“规律”。从讨论中了解到某“程序员水平考试”出了这类题目。这使我感到很不安。今年给一个教师学习班讲课,发现许多专业课教师也对这一基本问题也不甚明了,更觉得问题确实严重。因此整理出这篇短文供大家参考。后后记:4 年多过去了,许多新的和老的教科书仍然在不厌其烦地讨论在 C语言里原本并无意义的问题(如本文所指出的)。希望学习和使用 C语言的人不要陷入其中。=如果一个表达式的结果依赖于操作数的求值顺序,那这个表达式的行为(即结果)是无定义的。而使用标准没有定义的行为是错误的。所以应该修改表达式,使其与操作数的求值顺序无关。

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 生活休闲 > 社会民生

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报