黑马程序员技术交流社区

标题: 心得分享:优先级、结合性和表达式求值顺序 [打印本页]

作者: fantacyleo    时间: 2014-7-10 11:33
标题: 心得分享:优先级、结合性和表达式求值顺序
本帖最后由 fantacyleo 于 2014-8-11 12:45 编辑

编程语言的运算符多,功能自然就强,方便了程序员,但同时也带来了孰先孰后的困扰。在日常开发中,为可读性计,可以适当加括号。然而在求职过程中,企业经常喜欢用复杂的多运算符表达式考察你对语言的掌握水平。因此,记忆并理解运算符的优先级和结合性还是有必要的。记忆不说了,常识+背诵;我主要说一下理解问题,因为优先级和结合性的概念通常被大家和求值顺序混为一谈。

先说概念:

优先级:决定操作数(参与运算的变量、常量、字面值)与相邻的两个不同运算符之间的结合顺序
结合性:决定操作数与相邻的两个相同优先级运算符之间的结合顺序

比如:2 + 3 * 5。 +和*是与3相邻的不同运算符,3与它们的结合顺序由优先级决定。*的优先级高于+,因此编译器会把表达式转为:2 + (3 * 5)
比如:2 + 3 - 4。 对2来说,它肯定和+结合,而对3来说,到底和+还是和-结合呢?用我们学的数学来看,这无所谓,因为减法是加法的逆运算,-4可以转为+(-4),而加法满足结合律(a+b+c = a+(b+c)),怎么算都是1。但对编程语言,特别是C这种把整数分有符号和无符号的语言来说就不是这样了。无符号数下计算3-4得到的不是-1,而是一个很大的正数,这个结果和先算2+3是完全不同的。因此对C编译器来说,3到底和+还是和-结合是非常重要的,而这需要靠结合性决定。由于+、-是左结合(从左向右)的,因此,3和+结合

昨天有人问下面这个带三目运算符的表达式怎么求值
假设 a=1,b=2,c=3,d=4;
        a<b?a:c<d?a:d;

这个表达式怎么分析呢?首先,<的优先级高于三目运算符,因此表达式变为(a < b) ? a : (c < d) ? a : d。现在,表达式中有两个三目运算符,处于中间的(c<d)和哪个三目运算符结合?由于三目运算符是右结合(从右向左),因此(c<d)与右边的三目运算符结合,表达式变为(a < b) ? a : ( (c < d) ? a : d)。到此,没有再需要判断顺序和结合性的情况了,编译器可以开始求值了。

那么表达式求值顺序和优先级结合性有什么关系呢?可能很多人认为优先级和结合性决定了表达式求值顺序,比如认为2 + 3 * 5中*优先级高,所以先求3*5。实际上,在C语言中,编译器先求2的值还是先求3*5的值都是OK的,只是这个简单的例子看不出区别,如果换成这个式子就大不相同了:
  1. int  a = 3;
  2. a + ++a;
复制代码
按优先级,这个式子等价于a + (++a); 但是,如果你认为因为优先级所以++a一定先计算,那就错了。C语言标准没有规定是先算a还是先算++a,实际上,编译器先算a再算++a最后算a+(++a)并不违背优先级顺序,因此这样做的编译器是合乎C语言规范的。但这却给程序员带来了困扰:有的编译器上可能算出7(先算a),有的编译器可能算出8(先算++a)。论坛上有位同学实际测试了一下这个问题,他用了三种C编译器,给出了三个不同的结果http://bbs.itheima.com/thread-129127-1-1.html

所以,优先级和结合性决定且只决定表达式如何加括号,而不决定表达式的求值顺序。在C语言中,表达式的求值顺序一般是任意的


既然有一般就有特殊。C语言对4个运算符规定了表达式的求值顺序
a && b :先求a,只有a为真才会求b的值
a || b :只有a为假才会求b的值
a, b, c : 逗号运算符,从左到右依次求a、b、c的值。要特别注意的是,函数的参数列表中分隔多个参数的逗号不属于逗号运算符。也就是说,如果你这样调用函数:foo(a++, a),到底先算a++,还是先算a,这个顺序也没有保证。
a ? b : c 三目运算符,只有a为真才会求b的值,只有a为假才会求c的值

C语言发展至今,虽然已经标准化,但许多历史遗留问题是积重难返了,比如表达式求值顺序,比如数组下标越界不检查,解决的办法唯有程序避免写这样的表达式。

最后来个思考题吧,求这个表达式的值:
  1. int x = 3, y = 2;
  2. x > y ? 10 : ++y > 2 ? 20 : 30
复制代码




作者: 幕夏    时间: 2014-7-10 12:08
顶了,最后一个表达式明显是10啊。
作者: 零下_1°    时间: 2014-7-10 14:43
高手在民间啊
作者: 完美世界    时间: 2014-7-11 06:25
总结的到位!
作者: 丶白菜你个小番    时间: 2014-7-11 09:54
谢谢分享!
作者: 大坏蛋    时间: 2014-7-11 10:22
学习了,你让我知道了我是有多么的孤陋寡闻了,我需要静下心来看看书了
作者: 大坏蛋    时间: 2014-7-11 10:23
幕夏 发表于 2014-7-10 12:08
顶了,最后一个表达式明显是10啊。

嗯,应该是10吧。
作者: BOOM    时间: 2014-7-11 10:43
感谢楼主用心整理的分享,清晰明了,最后一题结果应该是十吧
作者: 大坏蛋    时间: 2014-7-11 10:44
顶一下,这么详细的解答,应该该让更多的人看到,有很多人在想当然啊,包括我
作者: 魇影    时间: 2014-7-11 10:47
学习了,以前都没注意竟然这么复杂
作者: 喵喵    时间: 2014-7-11 11:32
学习啦哈
作者: rocki    时间: 2014-7-11 12:02
感谢分享。
作者: 乐此不疲    时间: 2014-7-21 13:12
楼主这个总结很不错啊  学习了
作者: 心之信子    时间: 2014-7-25 21:57
学习了。。。
作者: zrtalent    时间: 2014-9-23 09:16
感谢分享




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2