Chinaunix首页 | 论坛 | 博客
  • 博客访问: 99244
  • 博文数量: 15
  • 博客积分: 1649
  • 博客等级: 上尉
  • 技术积分: 168
  • 用 户 组: 普通用户
  • 注册时间: 2010-10-12 10:43
文章分类

全部博文(15)

文章存档

2011年(5)

2010年(10)

分类: C/C++

2010-12-29 13:32:55

经常有人问类似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已经发生。

转载请注明出处。 

阅读(1927) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~