免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 8640 | 回复: 26
打印 上一主题 下一主题

[C] 优先级,结合性,序列点, 你理解清楚了么? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-12-29 15:24 |只看该作者 |倒序浏览
本帖最后由 donotblock 于 2010-12-29 19:27 编辑

经常有人问类似i=i++, c=d=c++, a=i++ * i++等表达式的值,每次还都能看到不少错误的回答。 理解这些问题需要弄清楚c语言的表达式求值(evaluation)过程。 今天就抛砖引玉了,希望能终结月经贴。
一个表达式可以分两部分来看:
副作用 - side effect, 我觉得效果这个词比较形象一点。 意思是一个表达式带来的影响
结果 - result , 就是表达式的值

比如i++, 副作用是i+1,结果是i本身。

然后是三个名词:
优先级 - precedence
结合性 - associativity
序列点 - sequence point




很多人错误的理解了优先级和结合性的意思,认为它们决定了一个表达式中各子表达式的求值顺序,这是错误理解开头所提问题的根源。  而实际上:


1.  优先级和结合性是的唯一作用是决定哪些操作数是属于些操作符。

2.  优先级和结合性不能表明哪些表达式先求值些后求值。

3.  序列点就是程序执行过程中的特定点,子表达式的求值顺序只被序列点决定。

4.  C语言只保证,到一个序列点的时候,这个序列点前面的所有side effect都已经完成,而且这个序列点后面的所有side effect都还没有发生。

5.  上一个序列点后到这一个序列点之间,各子表达式的求值顺序未定义。

6.  序列点包括:

     a> 函数调用(在参数处理完成,实际进入函数之前)

     b> 在操作符逻辑与(&&), 逻辑或(||),条件(?),逗号(, 函数参数列表里不算)的第一个操作数之后。

     c> 一个完整的表达式后面,比如分号后面或者if里面的控制表达式等。

7. 对于序列点,一个重要的原则是: 在上一个序列点后到这一个序列点之间最多改变一个对象的值一次。


例如表达式:

a=i + i++ * i++ - b;


由于++的优先级最高,*次之,+和-的优先级一样,但结合性是从左到右,所以这个表达式会被解析成:


a=(i + ((i++) * (i++))) - b;


这就是优先级和结合性的唯一作用,只是表明操作数应该往哪个操作符上靠。 至于其中的子表达式比如两个i++什么时候发生,什么顺序发生,都是未定义的,不确定的。

而像下面这个:

i++ && i++ && i++


其执行顺序就是确定的,因为&&是序列点,每到一个&&, 就可以保证其前面所有的side effect已经发生。


评分

参与人数 4可用积分 +24 收起 理由
zhujiang73 + 2
OwnWaterloo + 10 来晚了……
langue + 10 精品文章
wb112200 + 2

查看全部评分

论坛徽章:
0
2 [报告]
发表于 2010-12-29 15:29 |只看该作者
终于明白了 建议置精华!!

论坛徽章:
1
CU十二周年纪念徽章
日期:2013-10-24 15:41:34
3 [报告]
发表于 2010-12-29 15:30 |只看该作者
看了,是阿,这样的搞法有时候蛮烦人的。

论坛徽章:
0
4 [报告]
发表于 2010-12-29 16:34 |只看该作者
1.  优先级和结合性是的唯一作用是决定笔试客观题的分数。
2.  平时不要编写这么反人类的代码,还是用括号吧。

想终结月经贴,不可能。除非技术笔试不考这个——其实我真觉得这么没啥好考的,正确答案应该是E:我保证不会写这样的代码。

论坛徽章:
12
巳蛇
日期:2013-09-16 15:32:242015年辞旧岁徽章
日期:2015-03-03 16:54:152015年亚洲杯之约旦
日期:2015-02-11 14:38:37双鱼座
日期:2015-01-05 11:05:47戌狗
日期:2014-12-08 09:41:18戌狗
日期:2014-08-15 09:29:29双子座
日期:2014-08-05 09:17:17卯兔
日期:2014-06-08 15:32:18巳蛇
日期:2014-01-27 08:47:08白羊座
日期:2013-11-28 21:04:15巨蟹座
日期:2013-11-13 21:58:012015年亚洲杯之科威特
日期:2015-04-17 16:51:51
5 [报告]
发表于 2010-12-29 18:11 |只看该作者
本帖最后由 zhaohongjian000 于 2010-12-29 18:19 编辑

1.  优先级和结合性是的唯一作用是决定哪些操作数是属于那些操作符。
2.  优先级和结合性不能表明那些表达式先求值那些后求值。
----------------------------------------------------------------------------

  感觉这两点不正确,比如 a * b + c,由于*优先级高于+,所以a * b先被计算(当然,这里也可以解释为 * 的优先级使得a和b成为*的操作数)。

  再看这个:*p++,显然两个操作符都是针对p的,但语义究竟是*(p++)还是(*p)++由结合性决定。关于结合性,《C专家编程》上是这么解释的:1.它是仲裁者,在几个操作符具有相同的优先级时决定先执行哪一个。2.结合性只用于表达式中出现两个以上相同优先级的操作符的情况,用于消除歧义。根据结合性,代码:
  1. a = b = c
复制代码
的行为也是良好定义的,这个时候结合性决定后一个 = 先计算。

  我觉得楼主在表明自己观点的时候最好附上依据,比如ISO C文档中的原文,否则难以让人信服。我英语不好,查ISO文档有点困难,但我觉得关于结合性这一点,《C专家编程》里讲的应该没有问题。

论坛徽章:
0
6 [报告]
发表于 2010-12-29 19:12 |只看该作者
本帖最后由 donotblock 于 2010-12-29 19:17 编辑
1.  优先级和结合性是的唯一作用是决定哪些操作数是属于那些操作符。
2.  优先级和结合性不能表明那些表达 ...
zhaohongjian000 发表于 2010-12-29 18:11


我刚发过一份ANSI C标准http://bbs.chinaunix.net/thread-1838474-1-2.html

你可以去看里面的A.6.1 Unspecified behavior

The order in which expressions are evaluated --- in any order
conforming to the precedence rules, even in the presence of
parentheses ($3.3).


完美的解释了你的问题。 其它关于序列点,可以自己在文档里搜索一下

  1. a = b = c
复制代码
的确是良好定义的,因为它符合“同一个序列点改变一个对象值一次“的原则。

论坛徽章:
0
7 [报告]
发表于 2010-12-29 19:23 |只看该作者
写得很好,总结得非常全面。
按说这是常识性的入门知识
但是很可惜,多数C语言的初学者根本不知道
甚至他们中的很多人后来也不知道
国内的教科书和教师应该为那种月经贴感到羞愧


主帖的一处微瑕
就是表达的值

论坛徽章:
0
8 [报告]
发表于 2010-12-29 19:27 |只看该作者
回复 7# KBTiller


    谢谢,已经修正

论坛徽章:
0
9 [报告]
发表于 2010-12-29 19:39 |只看该作者
回复 7# KBTiller

您书上那部分解释的也很不错。

论坛徽章:
0
10 [报告]
发表于 2010-12-29 19:41 |只看该作者
回复 9# davelv

  谢谢!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP